diff options
author | nthnluu <nate1299@me.com> | 2024-01-28 21:20:27 -0500 |
---|---|---|
committer | nthnluu <nate1299@me.com> | 2024-01-28 21:20:27 -0500 |
commit | c63f340d90800895f007de64b7d2d14624263331 (patch) | |
tree | 2c0849fa597dd6da831c8707b6f2603403778d7b /kernel/include/fs |
Created student weenix repository
Diffstat (limited to 'kernel/include/fs')
-rw-r--r-- | kernel/include/fs/dirent.h | 25 | ||||
-rw-r--r-- | kernel/include/fs/fcntl.h | 18 | ||||
-rw-r--r-- | kernel/include/fs/file.h | 62 | ||||
-rw-r--r-- | kernel/include/fs/lseek.h | 5 | ||||
-rw-r--r-- | kernel/include/fs/open.h | 5 | ||||
-rw-r--r-- | kernel/include/fs/pipe.h | 10 | ||||
-rw-r--r-- | kernel/include/fs/ramfs/ramfs.h | 5 | ||||
-rw-r--r-- | kernel/include/fs/s5fs/s5fs.h | 145 | ||||
-rw-r--r-- | kernel/include/fs/s5fs/s5fs_privtest.h | 6 | ||||
-rw-r--r-- | kernel/include/fs/s5fs/s5fs_subr.h | 53 | ||||
-rw-r--r-- | kernel/include/fs/stat.h | 44 | ||||
-rw-r--r-- | kernel/include/fs/vfs.h | 162 | ||||
-rw-r--r-- | kernel/include/fs/vfs_privtest.h | 3 | ||||
-rw-r--r-- | kernel/include/fs/vfs_syscall.h | 39 | ||||
-rw-r--r-- | kernel/include/fs/vnode.h | 358 | ||||
-rw-r--r-- | kernel/include/fs/vnode_specials.h | 0 |
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 |