/dev/stdout support via a devfs
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 24 Aug 2010 00:03:50 +0000 (17:03 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:52 +0000 (17:35 -0700)
It's not a real FS - just KFS entries that have their f_op overriden.
It's a nice helper so processes can treat the stds as files.  /dev/stdin
is there, but doesn't do anything yet.

kern/include/devfs.h [new file with mode: 0644]
kern/include/kfs.h
kern/src/Makefrag
kern/src/devfs.c [new file with mode: 0644]
kern/src/init.c
kern/src/process.c
kern/src/syscall.c
kern/src/vfs.c
tests/file_test.c
tests/hello.c

diff --git a/kern/include/devfs.h b/kern/include/devfs.h
new file mode 100644 (file)
index 0000000..6979fc5
--- /dev/null
@@ -0,0 +1,18 @@
+/* Copyright (c) 2010 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Devfs: filesystem interfaces to devices.  For now, we just create the
+ * needed/discovered devices in KFS in its /dev/ folder. */
+
+#ifndef ROS_KERN_DEVFS_H
+#define ROS_KERN_DEVFS_H
+
+#include <vfs.h>
+
+void devfs_init(void);
+
+/* Exporting these for convenience */
+extern struct file *dev_stdin, *dev_stdout, *dev_stderr;
+
+#endif /* !ROS_KERN_DEVFS_H */
index 8321c19..7921437 100644 (file)
@@ -24,4 +24,65 @@ struct kfs_i_info {
        size_t                                  init_size;              /* file size on the backing store */
 };
 
+/* KFS VFS functions.  Exported for use by similar FSs (devices, for now) */
+struct super_block *kfs_get_sb(struct fs_type *fs, int flags,
+                               char *dev_name, struct vfsmount *vmnt);
+void kfs_kill_sb(struct super_block *sb);
+/* Page Map Operations */
+int kfs_readpage(struct file *file, struct page *page);
+/* Super Operations */
+struct inode *kfs_alloc_inode(struct super_block *sb);
+void kfs_dealloc_inode(struct inode *inode);
+void kfs_read_inode(struct inode *inode);
+void kfs_dirty_inode(struct inode *inode);
+void kfs_write_inode(struct inode *inode, bool wait);
+void kfs_put_inode(struct inode *inode);
+void kfs_drop_inode(struct inode *inode);
+void kfs_delete_inode(struct inode *inode);
+void kfs_put_super(struct super_block *sb);
+void kfs_write_super(struct super_block *sb);
+int kfs_sync_fs(struct super_block *sb, bool wait);
+int kfs_remount_fs(struct super_block *sb, int flags, char *data);
+void kfs_umount_begin(struct super_block *sb);
+/* inode_operations */
+int kfs_create(struct inode *dir, struct dentry *dentry, int mode,
+               struct nameidata *nd);
+struct dentry *kfs_lookup(struct inode *dir, struct dentry *dentry,
+                          struct nameidata *nd);
+int kfs_link(struct dentry *old_dentry, struct inode *dir,
+             struct dentry *new_dentry);
+int kfs_unlink(struct inode *dir, struct dentry *dentry);
+int kfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname);
+int kfs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+int kfs_rmdir(struct inode *dir, struct dentry *dentry);
+int kfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev);
+int kfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+               struct inode *new_dir, struct dentry *new_dentry);
+char *kfs_readlink(struct dentry *dentry);
+void kfs_truncate(struct inode *inode);
+int kfs_permission(struct inode *inode, int mode, struct nameidata *nd);
+/* dentry_operations */
+int kfs_d_revalidate(struct dentry *dir, struct nameidata *nd);
+int kfs_d_hash(struct dentry *dentry, struct qstr *name);
+int kfs_d_compare(struct dentry *dir, struct qstr *name1, struct qstr *name2);
+int kfs_d_delete(struct dentry *dentry);
+int kfs_d_release(struct dentry *dentry);
+void kfs_d_iput(struct dentry *dentry, struct inode *inode);
+/* file_operations */
+off_t kfs_llseek(struct file *file, off_t offset, int whence);
+int kfs_readdir(struct file *dir, struct dirent *dirent);
+int kfs_mmap(struct file *file, struct vm_region *vmr);
+int kfs_open(struct inode *inode, struct file *file);
+int kfs_flush(struct file *file);
+int kfs_release(struct inode *inode, struct file *file);
+int kfs_fsync(struct file *file, struct dentry *dentry, int datasync);
+unsigned int kfs_poll(struct file *file, struct poll_table_struct *poll_table);
+ssize_t kfs_readv(struct file *file, const struct iovec *vector,
+                  unsigned long count, off_t *offset);
+ssize_t kfs_writev(struct file *file, const struct iovec *vector,
+                  unsigned long count, off_t *offset);
+ssize_t kfs_sendpage(struct file *file, struct page *page, int offset,
+                     size_t size, off_t pos, int more);
+int kfs_check_flags(int flags);
+
 #endif /* !ROS_KERN_KFS_H */
index 0bd36fb..3efbbb4 100644 (file)
@@ -43,6 +43,7 @@ KERN_SRCFILES := $(KERN_ARCH_SRCFILES) \
                  $(KERN_SRC_DIR)/vfs.c \
                  $(KERN_SRC_DIR)/radix.c \
                  $(KERN_SRC_DIR)/umem.c \
+                 $(KERN_SRC_DIR)/devfs.c \
                  $(KERN_SRC_DIR)/testing.c \
                  $(KERN_SRC_DIR)/arsc.c
 
diff --git a/kern/src/devfs.c b/kern/src/devfs.c
new file mode 100644 (file)
index 0000000..ad3ff14
--- /dev/null
@@ -0,0 +1,127 @@
+/* Copyright (c) 2010 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Devfs: filesystem interfaces to devices.  For now, we just create the
+ * needed/discovered devices in KFS in its /dev/ folder, and only do this for
+ * stdin and stdout. */
+
+#include <devfs.h>
+#include <kfs.h>
+#include <error.h>
+#include <syscall.h>
+#include <process.h>
+#include <smp.h>
+#include <umem.h>
+
+/* These structs are declared again and initialized farther down */
+struct file_operations dev_f_op_stdin;
+struct file_operations dev_f_op_stdout;
+
+struct file *dev_stdin, *dev_stdout, *dev_stderr;
+
+/* Helper to build stdin, stdout, and stderr */
+static struct file *get_stdinout(char *name, int mode,
+                                 struct file_operations *fop)
+{
+       struct file *f_char_dev = do_file_open(name, O_CREAT, mode);
+       assert(f_char_dev);
+       /* Overwrite the f_op with our own f_ops */
+       f_char_dev->f_dentry->d_inode->i_fop = fop;
+       f_char_dev->f_op = fop;
+       return f_char_dev;
+}
+
+void devfs_init(void)
+{
+       int mode;
+       /* Make sure there is a dev directory */
+       struct dentry *dentry = lookup_dentry("/dev/", 0);      
+       if (!dentry) {
+               assert(!do_mkdir("/dev/", S_IRWXU | S_IRWXG | S_IRWXO));
+       } else {
+               kref_put(&dentry->d_kref);
+       }
+       /* Notice we don't kref_put().  We're storing the refs globally */
+       dev_stdin = get_stdinout("/dev/stdin", S_IRUSR | S_IRGRP | S_IROTH,
+                                &dev_f_op_stdin);
+       dev_stdout = get_stdinout("/dev/stdout", S_IWUSR | S_IWGRP | S_IWOTH,
+                                 &dev_f_op_stdout);
+       /* Note stderr uses the same f_op as stdout */
+       dev_stderr = get_stdinout("/dev/stderr", S_IWUSR | S_IWGRP | S_IWOTH,
+                                 &dev_f_op_stdout);
+}
+
+/* We provide a separate set of f_ops and pm_ops for devices (char for now), and
+ * this is the only thing that differs from the regular KFS.  We need to do some
+ * ghetto-overriding of these ops after we create them. */
+
+off_t dev_c_llseek(struct file *file, off_t offset, int whence)
+{
+       set_errno(EINVAL);
+       return -1;
+}
+
+ssize_t dev_stdin_read(struct file *file, char *buf, size_t count,
+                       off_t *offset)
+{
+       printk("[kernel] Tried to read %d bytes from stdin\n", count);
+       return -1;
+}
+
+ssize_t dev_stdout_write(struct file *file, const char *buf, size_t count,
+                         off_t *offset)
+{
+       char *t_buf;
+       struct proc *p = current;
+       if (p)
+               t_buf = user_strdup_errno(p, buf, count);
+       else
+               t_buf = (char*)buf;
+       if (!t_buf)
+               return -1;
+       printk("%s", t_buf);
+       return count;
+}
+
+/* we don't allow mmapping of any device file */
+int dev_mmap(struct file *file, struct vm_region *vmr)
+{
+       set_errno(EINVAL);
+       return -1;
+}
+
+/* Character device file ops */
+struct file_operations dev_f_op_stdin = {
+       dev_c_llseek,
+       dev_stdin_read,
+       0,      /* write - can't write to stdin */
+       kfs_readdir,    /* this will fail gracefully */
+       dev_mmap,
+       kfs_open,
+       kfs_flush,
+       kfs_release,
+       0,      /* fsync - makes no sense */
+       kfs_poll,
+       0,      /* readv */
+       0,      /* writev */
+       kfs_sendpage,
+       kfs_check_flags,
+};
+
+struct file_operations dev_f_op_stdout = {
+       dev_c_llseek,
+       0,      /* read - can't read stdout */
+       dev_stdout_write,
+       kfs_readdir,    /* this will fail gracefully */
+       dev_mmap,
+       kfs_open,
+       kfs_flush,
+       kfs_release,
+       0,      /* fsync - makes no sense */
+       kfs_poll,
+       0,      /* readv */
+       0,      /* writev */
+       kfs_sendpage,
+       kfs_check_flags,
+};
index eba2f84..c83bac2 100644 (file)
@@ -38,6 +38,7 @@
 #include <slab.h>
 #include <kfs.h>
 #include <vfs.h>
+#include <devfs.h>
 
 // zra: flag for Ivy
 int booting = 1;
@@ -81,6 +82,7 @@ void kernel_init(multiboot_info_t *mboot_info)
        file_init();
        page_check();
        vfs_init();
+       devfs_init();
        idt_init();
        kernel_msg_init();
        sysenter_init();
index 345f72f..6ff105f 100644 (file)
@@ -27,6 +27,7 @@
 #include <resource.h>
 #include <elf.h>
 #include <arsc_server.h>
+#include <devfs.h>
 
 /* Process Lists */
 struct proc_list proc_runnablelist = TAILQ_HEAD_INITIALIZER(proc_runnablelist);
@@ -331,12 +332,10 @@ error_t proc_alloc(struct proc **pp, struct proc *parent)
        p->open_files.max_fdset = NR_FILE_DESC_DEFAULT;
        p->open_files.fd = p->open_files.fd_array;
        p->open_files.open_fds = (struct fd_set*)&p->open_files.open_fds_init;
-       /* TODO: 0, 1, and 2 are reserved, but prob shouldn't do it this way.
-        * Whatever we do for stdin/out/err, we need to keep it in sync for created
-        * processes and forked processes (clone_files). */
-       p->open_files.next_fd = 3;
-       for (int i = 0; i < 3; i++)
-               SET_BITMASK_BIT(p->open_files.open_fds->fds_bits, i);
+       /* Connect to stdin, stdout, stderr */
+       assert(insert_file(&p->open_files, dev_stdin) == 0);
+       assert(insert_file(&p->open_files, dev_stdout) == 1);
+       assert(insert_file(&p->open_files, dev_stderr) == 2);
 
        atomic_inc(&num_envs);
        frontend_proc_init(p);
index 8c63eb0..d36b8af 100644 (file)
@@ -784,7 +784,11 @@ static intreg_t sys_read(struct proc *p, int fd, void *buf, int len)
                set_errno(EBADF);
                return -1;
        }
-       assert(file->f_op->read);
+       if (!file->f_op->read) {
+               kref_put(&file->f_kref);
+               set_errno(EINVAL);
+               return -1;
+       }
        /* TODO: (UMEM) currently, read() handles user memcpy issues, but we
         * probably should user_mem_check and pin the region here, so read doesn't
         * worry about it */
@@ -795,15 +799,6 @@ static intreg_t sys_read(struct proc *p, int fd, void *buf, int len)
 
 static intreg_t sys_write(struct proc *p, int fd, const void *buf, int len)
 {
-       /* Catch common usage of stdout and stderr.  No protections or anything. */
-       if (fd == 1) {
-               printk("[stdout]: %s\n", buf);
-               return len;
-       } else if (fd == 2) {
-               printk("[stderr]: %s\n", buf);
-               return len;
-       }
-       /* the real sys_write: */
        ssize_t ret;
        struct file *file = get_file_from_fd(&p->open_files, fd);
        if (!file) {
index 739217c..7d792f3 100644 (file)
@@ -1528,10 +1528,9 @@ struct file *put_file_from_fd(struct files_struct *open_files, int file_desc)
                        assert(file_desc < open_files->max_files);
                        file = open_files->fd[file_desc];
                        open_files->fd[file_desc] = 0;
+                       assert(file);
+                       kref_put(&file->f_kref);
                        CLR_BITMASK_BIT(open_files->open_fds->fds_bits, file_desc);
-                       /* the if case is due to files (stdin) without a *file yet */
-                       if (file)
-                               kref_put(&file->f_kref);
                }
        }
        spin_unlock(&open_files->lock);
@@ -1577,9 +1576,8 @@ void close_all_files(struct files_struct *open_files, bool cloexec)
                        if (cloexec && !(file->f_flags | O_CLOEXEC))
                                continue;
                        open_files->fd[i] = 0;
-                       /* the if case is due to files (stdin) without a *file yet */
-                       if (file)
-                               kref_put(&file->f_kref);
+                       assert(file);
+                       kref_put(&file->f_kref);
                        CLR_BITMASK_BIT(open_files->open_fds->fds_bits, i);
                }
        }
@@ -1601,9 +1599,8 @@ void clone_files(struct files_struct *src, struct files_struct *dst)
                        SET_BITMASK_BIT(dst->open_fds->fds_bits, i);
                        assert(i < dst->max_files && dst->fd[i] == 0);
                        dst->fd[i] = file;
-                       /* the if case is due to files (stdin) without a *file yet */
-                       if (file)
-                               kref_get(&file->f_kref, 1);
+                       assert(file);
+                       kref_get(&file->f_kref, 1);
                }
        }
        spin_unlock(&dst->lock);
index 2a58aee..8b01cb2 100644 (file)
@@ -1,4 +1,4 @@
-#include <rstdio.h> 
+#include <stdio.h> 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
index 148367e..7891ffb 100644 (file)
@@ -1,5 +1,5 @@
 #include <stdlib.h>
-#include <rstdio.h>
+#include <stdio.h>
 
 int main(int argc, char** argv)
 {