* Lawyers can sort out the copyrights and whatnot with these interfaces and
* structures. */
-#ifndef ROS_KERN_VFS_H
-#define ROS_KERN_VFS_H
+#pragma once
#include <ros/common.h>
+#include <ros/limits.h>
#include <sys/queue.h>
-#include <arch/bitmask.h>
+#include <sys/uio.h>
+#include <bitmask.h>
#include <kref.h>
-#include <timing.h>
+#include <time.h>
#include <radix.h>
+#include <hashtable.h>
+#include <pagemap.h>
+#include <blockdev.h>
+#include <fdtap.h>
/* ghetto preprocessor hacks (since proc includes vfs) */
struct page;
typedef int dev_t;
typedef int kdev_t;
typedef int ino_t;
-typedef long off_t; // out there in other .h's, but not in the kernel yet
-struct block_device {int x;};
struct io_writeback {int x;};
struct event_poll {int x;};
struct poll_table_struct {int x;};
#include <ros/fs.h>
-struct page_map; /* analagous to linux's address_space object */
-struct page_map_operations;
+/* Create flags are those used only during creation, and not saved for later
+ * lookup or use. Everything other than them is viewable via getfl */
+#define O_CREAT_FLAGS (O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC)
+/* These flags are those you can attempt to set via setfl for the VFS. */
+#define O_FCNTL_SET_FLAGS (O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME | \
+ O_NONBLOCK)
+
struct super_block;
struct super_operations;
struct dentry;
struct file_operations;
struct fs_type;
struct vfsmount;
-
-struct iovec {
- void *iov_base;
- size_t iov_len;
-};
+struct pipe_inode_info;
/* List def's we need */
TAILQ_HEAD(sb_tailq, super_block);
#define LOOKUP_CREATE 0x11 /* create a file if it doesn't exist */
#define LOOKUP_ACCESS 0x12 /* access / check user permissions */
-/* TODO: make our own versions (fucking octal) and put it in fcntl.h */
-/* File access modes for open and fcntl. */
-#define O_RDONLY 0 /* Open read-only. */
-#define O_WRONLY 1 /* Open write-only. */
-#define O_RDWR 2 /* Open read/write. */
-#define O_ACCMODE 3
-
-/* Bits OR'd into the second argument to open. */
-#define O_CREAT 00000100 /* not fcntl */
-#define O_EXCL 00000200 /* not fcntl */
-#define O_NOCTTY 00000400 /* not fcntl */
-#define O_TRUNC 00001000 /* not fcntl */
-#define O_APPEND 00002000
-#define O_NONBLOCK 00004000
-#define O_SYNC 00010000
-#define O_FSYNC O_SYNC
-#define O_ASYNC 00020000
-#define O_DIRECT 00040000 /* Direct disk access. */
-#define O_DIRECTORY 00200000 /* Must be a directory. */
-#define O_NOFOLLOW 00400000 /* Do not follow links. */
-#define O_NOATIME 01000000 /* Do not set atime. */
-#define O_CLOEXEC 02000000 /* Set close_on_exec. */
-#define O_CREAT_FLAGS (O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC)
-
-/* File creation modes (access controls) */
-#define S_IRWXU 00700 /* user (file owner) has read, write and execute perms */
-#define S_IRUSR 00400 /* user has read permission */
-#define S_IWUSR 00200 /* user has write permission */
-#define S_IXUSR 00100 /* user has execute permission */
-#define S_IRWXG 00070 /* group has read, write and execute permission */
-#define S_IRGRP 00040 /* group has read permission */
-#define S_IWGRP 00020 /* group has write permission */
-#define S_IXGRP 00010 /* group has execute permission */
-#define S_IRWXO 00007 /* others have read, write and execute permission */
-#define S_IROTH 00004 /* others have read permission */
-#define S_IWOTH 00002 /* others have write permission */
-#define S_IXOTH 00001 /* others have execute permission */
-
-/* fcntl flags that we support, keep in sync with glibc */
-#define F_DUPFD 0 /* Duplicate file descriptor */
-#define F_GETFD 1 /* Get file descriptor flags */
-#define F_SETFD 2 /* Set file descriptor flags */
-#define F_GETFL 3 /* Get file status flags */
-#define F_SETFL 4 /* Set file status flags */
-/* For F_[GET|SET]FD */
-#define FD_CLOEXEC 1
-
-/* Every object that has pages, like an inode or the swap (or even direct block
- * devices) has a page_map, tracking which of its pages are currently in memory.
- * It is a map, per object, from index to physical page frame. */
-struct page_map {
- struct inode *pm_host; /* inode of the owner, if any */
- struct radix_tree pm_tree; /* tracks present pages */
- spinlock_t pm_tree_lock; /* spinlock => we can't block */
- unsigned long pm_num_pages; /* how many pages are present */
- struct page_map_operations *pm_op;
- unsigned int pm_flags;
- /*... and private lists, backing block dev info, other mappings, etc. */
-};
-
-/* Operations performed on a page_map. These are usually FS specific, which
- * get assigned when the inode is created.
- * Will fill these in as they are created/needed/used. */
-struct page_map_operations {
- int (*readpage) (struct file *, struct page *); /* read from backing store*/
-/* readpages: read a list of pages
- writepage: write from a page to its backing store
- writepages: write a list of pages
- sync_page: start the IO of already scheduled ops
- set_page_dirty: mark the given page dirty
- prepare_write: prepare to write (disk backed pages)
- commit_write: complete a write (disk backed pages)
- bmap: get a logical block number from a file block index
- invalidate page: invalidate, part of truncating
- release page: prepare to release
- direct_io: bypass the page cache */
-};
-
/* Superblock: Specific instance of a mounted filesystem. All synchronization
* is done with the one spinlock. */
struct inode_tailq s_inodes; /* all inodes */
struct inode_tailq s_dirty_i; /* dirty inodes */
struct io_wb_tailq s_io_wb; /* writebacks */
- struct dentry_slist s_anon_d; /* anonymous dentries */
struct file_tailq s_files; /* assigned files */
+ struct dentry_tailq s_lru_d; /* unused dentries (in dcache)*/
+ spinlock_t s_lru_lock;
+ struct hashtable *s_dcache; /* dentry cache */
+ spinlock_t s_dcache_lock;
+ struct hashtable *s_icache; /* inode cache */
+ spinlock_t s_icache_lock;
struct block_device *s_bdev;
TAILQ_ENTRY(super_block) s_instances; /* list of sbs of this fs type*/
char s_name[32];
struct super_operations {
struct inode *(*alloc_inode) (struct super_block *sb);
- void (*destroy_inode) (struct inode *); /* dealloc. might need more */
+ void (*dealloc_inode) (struct inode *);
void (*read_inode) (struct inode *);
void (*dirty_inode) (struct inode *);
void (*write_inode) (struct inode *, bool);
void (*umount_begin) (struct super_block *);/* called by NFS */
};
-#define FS_I_FILE 0x01
-#define FS_I_DIR 0x02
-#define FS_I_SYMLINK 0x03
+/* Sets the type of file, IAW the bits in ros/fs.h */
+#define SET_FTYPE(mode, type) ((mode) = ((mode) & ~__S_IFMT) | (type))
+
+/* Will need a bunch of states/flags for an inode. TBD */
+#define I_STATE_DIRTY 0x001
/* Inode: represents a specific file */
struct inode {
struct dentry_tailq i_dentry; /* all dentries pointing here*/
unsigned long i_ino;
struct kref i_kref;
- int i_mode; /* access mode */
- unsigned short i_type; /* file type */
+ int i_mode; /* access mode and file type */
unsigned int i_nlink; /* hard links */
uid_t i_uid;
gid_t i_gid;
struct inode_operations *i_op;
struct file_operations *i_fop;
struct super_block *i_sb;
- struct page_map *i_mapping; /* usually points to i_data */
+ struct page_map *i_mapping; /* usually points to i_pm */
struct page_map i_pm; /* this inode's page cache */
union {
struct pipe_inode_info *i_pipe;
};
#define DNAME_INLINE_LEN 32
+
+/* Dentry flags. All negatives are also unused. */
+#define DENTRY_USED 0x01 /* has a kref > 0 */
+#define DENTRY_NEGATIVE 0x02 /* cache of a failed lookup */
+#define DENTRY_DYING 0x04 /* should be freed on release */
+
/* Dentry: in memory object, corresponding to an element of a path. E.g. /,
* usr, bin, and vim are all dentries. All have inodes. Vim happens to be a
* file instead of a directory.
struct vfsmount *d_mounted_fs; /* fs mounted here */
struct dentry *d_parent;
struct qstr d_name; /* pts to iname and holds hash*/
- SLIST_ENTRY(dentry) d_hash; /* link for the dcache */
- struct dentry_slist d_bucket; /* hash bucket of this dentry */
char d_iname[DNAME_INLINE_LEN];
void *d_fs_info;
};
+/* Checks is a struct dentry pointer if the root.
+ */
+#define DENTRY_IS_ROOT(d) ((d) == (d)->d_parent)
+
/* not sure yet if we want to call delete when refcnt == 0 (move it to LRU) or
* when its time to remove it from the dcache. */
struct dentry_operations {
struct kref f_kref;
unsigned int f_flags; /* O_APPEND, etc */
int f_mode; /* O_RDONLY, etc */
- off_t f_pos; /* offset / file pointer */
+ off64_t f_pos; /* offset / file pointer */
unsigned int f_uid;
unsigned int f_gid;
int f_error;
struct event_poll_tailq f_ep_links;
spinlock_t f_ep_lock;
- void *f_fs_info; /* tty driver hook */
+ void *f_privdata; /* tty/socket driver hook */
struct page_map *f_mapping; /* page cache mapping */
/* Ghetto appserver support */
};
struct file_operations {
- off_t (*llseek) (struct file *, off_t, int);
- ssize_t (*read) (struct file *, char *, size_t, off_t *);
- ssize_t (*write) (struct file *, const char *, size_t, off_t *);
+ int (*llseek) (struct file *, off64_t, off64_t *, int);
+ ssize_t (*read) (struct file *, char *, size_t, off64_t *);
+ ssize_t (*write) (struct file *, const char *, size_t, off64_t *);
int (*readdir) (struct file *, struct dirent *);
int (*mmap) (struct file *, struct vm_region *);
int (*open) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long,
- off_t *);
+ off64_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long,
- off_t *);
- ssize_t (*sendpage) (struct file *, struct page *, int, size_t, off_t, int);
+ off64_t *);
+ ssize_t (*sendpage) (struct file *, struct page *, int, size_t, off64_t,
+ int);
int (*check_flags) (int flags); /* most FS's ignore this */
};
struct namespace *mnt_namespace;
};
+struct pipe_inode_info
+{
+ char *p_buf;
+ size_t p_rd_off;
+ size_t p_wr_off;
+ unsigned int p_nr_readers;
+ unsigned int p_nr_writers;
+ struct cond_var p_cv;
+};
+
/* Per-process structs */
#define NR_OPEN_FILES_DEFAULT 32
#define NR_FILE_DESC_DEFAULT 32
-/* keep this in sync with glibc's fd_setsize */
-#define NR_FILE_DESC_MAX 1024
/* Bitmask for file descriptors, big for when we exceed the initial small. We
* could just use the fd_array to check for openness instead of the bitmask,
* but eventually we might want to use the bitmasks for other things (like
* which files are close_on_exec. */
-struct fd_set {
+
+typedef struct fd_set {
uint8_t fds_bits[BYTES_FOR_BITMASK(NR_FILE_DESC_MAX)];
-};
+} fd_set;
+
+
struct small_fd_set {
uint8_t fds_bits[BYTES_FOR_BITMASK(NR_FILE_DESC_DEFAULT)];
};
+/* Helper macros to manage fd_sets */
+#define FD_SET(n, p) ((p)->fds_bits[(n)/8] |= (1 << ((n) & 7)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/8] &= ~(1 << ((n) & 7)))
+#define FD_ISSET(n,p) ((p)->fds_bits[(n)/8] & (1 << ((n) & 7)))
+#define FD_ZERO(p) memset((void*)(p),0,sizeof(*(p)))
+
+/* Describes an open file. We need this, since the FD flags are supposed to be
+ * per file descriptor, not per file (like the file status flags). */
+struct chan; /* from 9ns */
+struct file_desc {
+ struct file *fd_file;
+ struct chan *fd_chan;
+ unsigned int fd_flags;
+ struct fd_tap *fd_tap;
+};
+
/* All open files for a process */
-struct files_struct {
+struct fd_table {
spinlock_t lock;
+ bool closed;
int max_files; /* max files ptd to by fd */
int max_fdset; /* max of the current fd_set */
- int next_fd; /* next number available */
- struct file **fd; /* initially pts to fd_array */
+ int hint_min_fd; /* <= min available fd */
+ struct file_desc *fd; /* initially pts to fd_array */
struct fd_set *open_fds; /* init, pts to open_fds_init */
struct small_fd_set open_fds_init;
- struct file *fd_array[NR_OPEN_FILES_DEFAULT];
+ struct file_desc fd_array[NR_OPEN_FILES_DEFAULT];
};
-/* Process specific filesysten info */
+/* Process specific filesystem info */
struct fs_struct {
spinlock_t lock;
int umask;
extern spinlock_t super_blocks_lock;
extern struct fs_type_tailq file_systems; /* lock this if it's dynamic */
extern struct namespace default_ns;
-// TODO: should have a dentry_htable or something. we have the structs built
-// in to the dentry right now (linux style).
-extern struct dentry_slist dcache;
-extern spinlock_t dcache_lock;
/* Slab caches for common objects */
extern struct kmem_cache *dentry_kcache;
void vfs_init(void);
void qstr_builder(struct dentry *dentry, char *l_name);
char *file_name(struct file *file);
+char *dentry_path(struct dentry *dentry, char *path, size_t max_size);
int path_lookup(char *path, int flags, struct nameidata *nd);
void path_release(struct nameidata *nd);
+int mount_fs(struct fs_type *fs, char *dev_name, char *path, int flags);
+
+static inline char *file_abs_path(struct file *f, char *path, size_t max_size)
+{
+ return dentry_path(f->f_dentry, path, max_size);
+}
/* Superblock functions */
struct super_block *get_sb(void);
void *d_fs_info);
/* Dentry Functions */
+struct dentry *get_dentry_with_ops(struct super_block *sb,
+ struct dentry *parent, char *name,
+ struct dentry_operations *d_op);
struct dentry *get_dentry(struct super_block *sb, struct dentry *parent,
char *name);
-void dcache_put(struct dentry *dentry);
void dentry_release(struct kref *kref);
+void __dentry_free(struct dentry *dentry);
struct dentry *lookup_dentry(char *path, int flags);
+struct dentry *dcache_get(struct super_block *sb, struct dentry *what_i_want);
+void dcache_put(struct super_block *sb, struct dentry *key_val);
+struct dentry *dcache_remove(struct super_block *sb, struct dentry *key);
+void dcache_prune(struct super_block *sb, bool negative_only);
+int generic_dentry_hash(struct dentry *dentry, struct qstr *qstr);
/* Inode Functions */
struct inode *get_inode(struct dentry *dentry);
+void load_inode(struct dentry *dentry, unsigned long ino);
int create_file(struct inode *dir, struct dentry *dentry, int mode);
int create_dir(struct inode *dir, struct dentry *dentry, int mode);
int create_symlink(struct inode *dir, struct dentry *dentry,
int check_perms(struct inode *inode, int access_mode);
void inode_release(struct kref *kref);
void stat_inode(struct inode *inode, struct kstat *kstat);
+struct inode *icache_get(struct super_block *sb, unsigned long ino);
+void icache_put(struct super_block *sb, struct inode *inode);
+struct inode *icache_remove(struct super_block *sb, unsigned long ino);
/* File-ish functions */
ssize_t generic_file_read(struct file *file, char *buf, size_t count,
- off_t *offset);
+ off64_t *offset);
ssize_t generic_file_write(struct file *file, const char *buf, size_t count,
- off_t *offset);
+ off64_t *offset);
ssize_t generic_dir_read(struct file *file, char *u_buf, size_t count,
- off_t *offset);
+ off64_t *offset);
+struct file *alloc_file(void);
struct file *do_file_open(char *path, int flags, int mode);
int do_symlink(char *path, const char *symname, int mode);
int do_link(char *old_path, char *new_path);
-int do_file_access(char *path, int mode);
+int do_unlink(char *path);
+int do_access(char *path, int mode);
+int do_file_chmod(struct file *file, int mode);
+int do_mkdir(char *path, int mode);
+int do_rmdir(char *path);
+int do_pipe(struct file **pipe_files, int flags);
+int do_rename(char *old_path, char *new_path);
+int do_truncate(struct inode *inode, off64_t len);
struct file *dentry_open(struct dentry *dentry, int flags);
void file_release(struct kref *kref);
-
-/* Page cache functions */
-struct page *pm_find_page(struct page_map *pm, unsigned long index);
-int pm_insert_page(struct page_map *pm, unsigned long index, struct page *page);
-int pm_remove_page(struct page_map *pm, struct page *page);
-int file_load_page(struct file *file, unsigned long index, struct page **pp);
+ssize_t kread_file(struct file *file, void *buf, size_t sz);
+void *kread_whole_file(struct file *file);
/* Process-related File management functions */
-struct file *get_file_from_fd(struct files_struct *open_files, int fd);
-struct file *put_file_from_fd(struct files_struct *open_files, int file_desc);
-int insert_file(struct files_struct *open_files, struct file *file);
-void close_all_files(struct files_struct *open_files, bool cloexec);
-void clone_files(struct files_struct *src, struct files_struct *dst);
+void *lookup_fd(struct fd_table *fdt, int fd, bool incref, bool vfs);
+int insert_obj_fdt(struct fd_table *fdt, void *obj, int low_fd, int fd_flags,
+ bool must_use_low, bool vfs);
+bool close_fd(struct fd_table *fdt, int fd);
+void close_fdt(struct fd_table *open_files, bool cloexec);
+void clone_fdt(struct fd_table *src, struct fd_table *dst);
+
+struct file *get_file_from_fd(struct fd_table *open_files, int fd);
+void put_file_from_fd(struct fd_table *open_files, int file_desc);
+int insert_file(struct fd_table *open_files, struct file *file, int low_fd,
+ bool must, bool cloexec);
+int do_chdir(struct fs_struct *fs_env, char *path);
+int do_fchdir(struct fs_struct *fs_env, struct file *file);
+char *do_getcwd(struct fs_struct *fs_env, char **kfree_this, size_t cwd_l);
/* Debugging */
+void print_kstat(struct kstat *kstat);
int ls_dash_r(char *path);
-
-#endif /* ROS_KERN_VFS_H */
+extern struct inode_operations dummy_i_op;
+extern struct dentry_operations dummy_d_op;