sys_open() and sys_close()
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 28 Jul 2010 03:15:35 +0000 (20:15 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:49 +0000 (17:35 -0700)
A process can open and close files.  There's some refcounting issues,
which will be worked on soonish.

kern/include/monitor.h
kern/include/vfs.h
kern/src/kfs.c
kern/src/monitor.c
kern/src/process.c
kern/src/syscall.c
kern/src/vfs.c
tests/file_test.c

index f355ea5..08a5b9e 100644 (file)
@@ -29,5 +29,6 @@ int mon_notify(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
 int mon_measure(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
 int mon_trace(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
 int mon_monitor(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
+int mon_fs(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
 
 #endif // !ROS_KERN_MONITOR_H
index 9102abf..12cb53c 100644 (file)
@@ -75,11 +75,12 @@ TAILQ_HEAD(event_poll_tailq, event_poll);
 TAILQ_HEAD(vfsmount_tailq, vfsmount);
 TAILQ_HEAD(fs_type_tailq, fs_type);
 
-/* Linux's quickstring - saves recomputing the hash and length. */
+/* Linux's quickstring - saves recomputing the hash and length.  Note the length
+ * is the non-null-terminated length, as you'd get from strlen(). (for now) */
 struct qstr {
     unsigned int hash;
     unsigned int len;
-    const char *name;
+    char *name;
 };
 
 /* Helpful structure to pass around during lookup operations.  At each point,
@@ -111,6 +112,24 @@ struct nameidata {
 #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        0100 /* not fcntl */
+#define O_EXCL         0200 /* not fcntl */
+#define O_NOCTTY       0400 /* not fcntl */
+#define O_TRUNC       01000 /* not fcntl */
+#define O_APPEND      02000
+#define O_NONBLOCK    04000
+#define O_SYNC       010000
+#define O_FSYNC      O_SYNC
+#define O_ASYNC      020000
+
 /* 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. */
@@ -204,11 +223,11 @@ struct inode {
        gid_t                                           i_gid;
        kdev_t                                          i_rdev;                 /* real device node */
        size_t                                          i_size;
+       unsigned long                           i_blksize;
+       unsigned long                           i_blocks;               /* filesize in blocks */
        struct timespec                         i_atime;
        struct timespec                         i_mtime;
        struct timespec                         i_ctime;
-       unsigned long                           i_blksize;
-       unsigned long                           i_blocks;               /* filesize in blocks */
        spinlock_t                                      i_lock;
        struct inode_operations         *i_op;
        struct file_operations          *i_fop;
@@ -300,8 +319,8 @@ struct file {
        struct vfsmount                         *f_vfsmnt;
        struct file_operations          *f_op;
        atomic_t                                        f_refcnt;
-       unsigned int                            f_flags;
-       int                                                     f_mode;
+       unsigned int                            f_flags;                /* O_APPEND, etc */
+       int                                                     f_mode;                 /* O_RDONLY, etc */
        off_t                                           f_pos;                  /* offset / file pointer */
        unsigned int                            f_uid;
        unsigned int                            f_gid;
@@ -440,6 +459,7 @@ void init_sb(struct super_block *sb, struct vfsmount *vmnt,
 struct dentry *get_dentry(struct super_block *sb, struct dentry *parent,
                           char *name);
 void dcache_put(struct dentry *dentry);
+void free_dentry(struct dentry *dentry);
 
 /* Inode Functions */
 int check_perms(struct inode *inode, int access_mode);
@@ -449,6 +469,8 @@ ssize_t generic_file_read(struct file *file, char *buf, size_t count,
                           off_t *offset);
 ssize_t generic_file_write(struct file *file, const char *buf, size_t count,
                            off_t *offset);
+struct file *do_file_open(char *path, int flags, int mode);
+int do_file_close(struct file *file);
 
 /* Page cache functions */
 struct page *pm_find_page(struct page_map *pm, unsigned long index);
@@ -460,5 +482,6 @@ int file_load_page(struct file *file, unsigned long index, struct page **pp);
 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);
 
 #endif /* ROS_KERN_VFS_H */
index 35b847e..7e0eab0 100644 (file)
@@ -144,7 +144,8 @@ int kfs_readpage(struct file *file, struct page *page)
 
 /* creates and initializes a new inode.  generic fields are filled in.  specific
  * fields are filled in in read_inode() based on what's on the disk for a given
- * i_no.  i_no is set by the caller. */
+ * i_no.  i_no is set by the caller.  Note that this means this inode can be for
+ * an inode that is already on disk, or it can be used when creating. */
 struct inode *kfs_alloc_inode(struct super_block *sb)
 {
        /* arguably, we can avoid some of this init by using the slab/cache */
@@ -294,16 +295,22 @@ struct inode *kfs_create_generic(struct inode *dir, struct dentry *dentry,
        struct inode *inode = kfs_alloc_inode(dentry->d_sb);
        dentry->d_inode = inode;                /* inode ref stored here */
        TAILQ_INSERT_TAIL(&inode->i_dentry, dentry, d_alias); /* stored dentry ref*/
+       atomic_inc(&dentry->d_refcnt);  /* TODO: REF/KREF */
+       /* Need to finish the dentry */
+       dentry->d_op = &kfs_d_op;
+       dentry->d_fs_info = 0;
        inode->i_mode = mode;
        inode->i_ino = kfs_get_free_ino();
        inode->i_nlink = 1;
+       inode->i_size = 0;
+       inode->i_blocks = 0;
        inode->i_atime.tv_sec = 0;              /* TODO: now! */
        inode->i_ctime.tv_sec = 0;              /* TODO: now! */
        inode->i_mtime.tv_sec = 0;              /* TODO: now! */
        inode->i_atime.tv_nsec = 0;             /* are these supposed to be the extra ns? */
        inode->i_ctime.tv_nsec = 0;
        inode->i_mtime.tv_nsec = 0;
-       inode->i_flags = 0;;
+       inode->i_bdev = inode->i_sb->s_bdev;
        return inode;
 }
 
@@ -371,10 +378,7 @@ struct dentry *kfs_lookup(struct inode *dir, struct dentry *dentry,
        /* no match, consider caching the negative result, freeing the
         * dentry, etc */
        printd("Not Found %s!!\n", dentry->d_name.name);
-       /* TODO: Cache, negatively... */
-       //dcache_put(dentry);                   /* TODO: should set a d_flag too */
-       /* if we're not caching it, we should free it */
-       kmem_cache_free(dentry_kcache, dentry);
+       free_dentry(dentry);
        return 0;
 }
 
@@ -505,9 +509,6 @@ int kfs_d_delete(struct dentry *dentry)
 /* Called when it's about to be slab-freed */
 int kfs_d_release(struct dentry *dentry)
 {
-       /* TODO: check the boundaries on this. */
-       if (dentry->d_name.len > DNAME_INLINE_LEN)
-               kfree((void*)dentry->d_name.name);
        return -1;
 }
 
@@ -799,9 +800,9 @@ static int __add_kfs_entry(struct dentry *parent, char *path,
                       parent->d_name.name, c_bhdr->c_filestart, c_bhdr->c_filesize);
                /* Init the dentry for this path */
                dentry = get_dentry(parent->d_sb, parent, path);
-               dentry->d_op = &kfs_d_op;
                dcache_put(dentry);                     /* TODO: should set a d_flag too */
                /* build the inode */
+               /* XXX: note we use an unrefcnt'd inode here (grabbing the dentry's) */
                if (!c_bhdr->c_filesize) {
                        /* we are a directory.  Note that fifos might look like dirs... */
                        kfs_mkdir(parent->d_inode, dentry, c_bhdr->c_mode);
index 5773082..7f03f24 100644 (file)
@@ -18,7 +18,6 @@
 #include <pmap.h>
 #include <kdebug.h>
 #include <testing.h>
-#include <kfs.h>
 #include <manager.h>
 #include <schedule.h>
 #include <resource.h>
@@ -59,6 +58,7 @@ static command_t (RO commands)[] = {
        { "measure", "Run a specific measurement", mon_measure},
        { "trace", "Run a specific measurement", mon_trace},
        { "monitor", "Run the monitor on another core", mon_monitor},
+       { "fs", "Filesystem Diagnostics", mon_fs},
 };
 #define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))
 
@@ -278,7 +278,7 @@ int mon_bin_ls(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
 int mon_bin_run(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
 {
        if (argc != 2) {
-               printk("Usage: kfs_run FILENAME\n");
+               printk("Usage: bin_run FILENAME\n");
                return 1;
        }
        struct file *program;
@@ -762,3 +762,31 @@ void monitor(trapframe_t *tf) {
                }
        }
 }
+
+int mon_fs(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
+{
+       /* this assumes one mounted FS at the NS root */
+       struct super_block *sb = default_ns.root->mnt_root->d_inode->i_sb;
+       struct file *i;
+       if (argc < 2) {
+               printk("Usage: fs OPTION\n");
+               printk("\topen: show all open files\n");
+               printk("\tpid: proc PID's fs crap placeholder\n");
+               return 1;
+       }
+       if (!strcmp(argv[1], "open")) {
+               printk("Open Files:\n----------------------------\n");
+               TAILQ_FOREACH(i, &sb->s_files, f_list)
+                       printk("File: %08p, %s, Refs: %d\n", i, file_name(i), i->f_refcnt);
+       } else if (!strcmp(argv[1], "pid")) {
+               if (argc != 3) {
+                       printk("Give me a pid number.\n");
+                       return 1;
+               }
+               /* whatever.  placeholder. */
+       } else {
+               printk("Bad option\n");
+               return 1;
+       }
+       return 0;
+}
index ec4c3b7..e470358 100644 (file)
@@ -312,6 +312,7 @@ error_t proc_alloc(struct proc **pp, struct proc *parent)
        atomic_inc(&p->fs_env.root->d_refcnt);
        p->fs_env.pwd = parent ? parent->fs_env.pwd : p->fs_env.root;
        atomic_inc(&p->fs_env.pwd->d_refcnt);
+       memset(&p->open_files, 0, sizeof(p->open_files));       /* slightly ghetto */
        spinlock_init(&p->open_files.lock);
        p->open_files.max_files = NR_OPEN_FILES_DEFAULT;
        p->open_files.max_fdset = NR_FILE_DESC_DEFAULT;
@@ -356,16 +357,16 @@ static void __proc_free(struct proc *p)
        // All parts of the kernel should have decref'd before __proc_free is called
        assert(p->env_refcnt == 0);
 
-       frontend_proc_free(p);
-
-       // Free any colors allocated to this process
+       close_all_files(&p->open_files);
+       frontend_proc_free(p);  /* TODO: please remove me one day */
+       /* Free any colors allocated to this process */
        if(p->cache_colors_map != global_cache_colors_map) {
                for(int i=0; i<llc_cache->num_colors; i++)
                        cache_color_free(llc_cache, p->cache_colors_map);
                cache_colors_map_free(p->cache_colors_map);
        }
 
-       // Flush all mapped pages in the user portion of the address space
+       /* Flush all mapped pages in the user portion of the address space */
        env_user_mem_free(p, 0, UVPT);
        /* These need to be free again, since they were allocated with a refcnt. */
        free_cont_pages(p->procinfo, LOG2_UP(PROCINFO_NUM_PAGES));
@@ -1530,6 +1531,15 @@ void print_proc_info(pid_t pid)
        for (int i = 0; i < MAX_NUM_RESOURCES; i++)
                printk("\tRes type: %02d, amt wanted: %08d, amt granted: %08d\n", i,
                       p->resources[i].amt_wanted, p->resources[i].amt_granted);
+       printk("Open Files:\n");
+       struct files_struct *files = &p->open_files;
+       spin_lock(&files->lock);
+       for (int i = 0; i < files->max_files; i++)
+               if (files->fd_array[i]) {
+                       printk("\tFD: %02d, File: %08p, File name: %s\n", i,
+                              files->fd_array[i], file_name(files->fd_array[i]));
+               }
+       spin_unlock(&files->lock);
        /* No one cares, and it clutters the terminal */
        //printk("Vcore 0's Last Trapframe:\n");
        //print_trapframe(&p->env_tf);
index 90556e8..7b3819d 100644 (file)
@@ -372,6 +372,8 @@ static ssize_t sys_fork(env_t* e)
                set_errno(current_tf,ENOMEM);
                return -1;
        }
+       
+       /* TODO: copy all open files, except O_CLOEXEC */
 
        __proc_set_state(env, PROC_RUNNABLE_S);
        schedule_proc(env);
@@ -851,23 +853,42 @@ intreg_t sys_pread(struct proc* p, int fd, void* buf, int len, int offset)
        return ret;
 }
 
-intreg_t sys_open(struct proc* p, const char* path, int oflag, int mode)
+/* Checks args/reads in the path, opens the file, and inserts it into the
+ * process's open file list. 
+ *
+ * TODO: take the path length */
+intreg_t sys_open(struct proc *p, const char *path, int oflag, int mode)
 {
-       printd("File Open, p: %p, path: %s, oflag: %d, mode: 0x%x\n", p, path, oflag, mode);
-       char* fn = user_strdup_errno(p,path,PGSIZE);
-       if(fn == NULL) {
-               printd("File Open, user_strdup_errno failed\n");
+       int fd = 0;
+       struct file *file;
+
+       char *t_path = user_strdup_errno(p, path, PGSIZE);
+       if (t_path == NULL)
+               return -1;
+       file = do_file_open(t_path, oflag, mode);
+       user_memdup_free(p, t_path);
+       if (!file)
+               return -1;
+       fd = insert_file(&p->open_files, file); /* stores the ref to file */
+       atomic_dec(&file->f_refcnt);    /* TODO: REF / KREF */
+       if (fd < 0) {
+               warn("File insertion failed");
                return -1;
        }
-       printd("File Open, About to open\n");
-       int ret = ufe(open,PADDR(fn),oflag,mode,0);
-       printd("File Open, res=%d\n", ret);
-       user_memdup_free(p,fn);
-       return ret;
+       printd("File Open, res=%d\n", fd);
+       return fd;
 }
-intreg_t sys_close(struct proc* p, int fd)
+
+intreg_t sys_close(struct proc *p, int fd)
 {
-       return ufe(close,fd,0,0,0);
+       struct file *file = put_file_from_fd(&p->open_files, fd);
+       if (!file) {
+               set_errno(current_tf, EBADF);
+               return -1;
+       }
+       /* TEMP TEST */
+       assert(!file->f_refcnt);
+       return 0;
 }
 
 #define NEWLIB_STAT_SIZE 64
index 7115c36..613c9db 100644 (file)
@@ -107,11 +107,6 @@ void vfs_init(void)
        default_ns.root = mount_fs(&kfs_fs_type, "RAM", NULL, 0, &default_ns);
 
        printk("vfs_init() completed\n");
-       /*
-       put structs and friends in struct proc, and init in proc init
-       */
-       // LOOKUP: follow_mount, follow_link, etc
-       // pains in the ass for having .. or . in the middle of the path
 }
 
 /* Builds / populates the qstr of a dentry based on its d_iname.  If there is an
@@ -248,11 +243,16 @@ static int link_path_walk(char *path, struct nameidata *nd)
                link = next_slash + 1;
        }
        /* now, we're on the last link of the path */
-       /* if we just want the parent, leave now.  linux does some stuff with saving
-        * the name of the link (last) and the type (last_type), which we'll do once
-        * i see the need for it. */
-       if (nd->flags & LOOKUP_PARENT)
+       /* if we just want the parent, leave now.  and save the name of the link
+        * (last) and the type (last_type).  Note that using the qstr in this manner
+        * only allows us to use the qstr as long as the path is a valid string. */
+       if (nd->flags & LOOKUP_PARENT) {
+               /* consider using a slimmer qstr_builder for this */
+               nd->last.name = link;
+               nd->last.len = strlen(link);
+               nd->last.hash = nd->dentry->d_op->d_hash(nd->dentry, &nd->last);
                return 0;
+       }
        /* deal with some weird cases with . and .. (completely untested) */
        if (!strcmp(".", link))
                return 0;
@@ -272,8 +272,11 @@ static int link_path_walk(char *path, struct nameidata *nd)
 }
 
 /* Given path, return the inode for the final dentry.  The ND should be
- * initialized for the first call - specifically, we need the intent and
- * potentially a LOOKUP_PARENT.
+ * initialized for the first call - specifically, we need the intent. 
+ * LOOKUP_PARENT and friends go in this flags var.
+ *
+ * TODO: this should consider the intent.  Note that creating requires writing
+ * to the last directory.
  *
  * Need to be careful too.  While the path has been copied-in to the kernel,
  * it's still user input.  */
@@ -310,7 +313,8 @@ void path_release(struct nameidata *nd)
 }
 
 /* Seems convenient: Given a path, return the appropriate file.  The reference
- * returned is refcounted (which is done by open()). */
+ * returned is refcounted (which is done by open()).  TODO: make sure the called
+ * functions do error checking and propagate errno. */
 struct file *path_to_file(char *path)
 {
        struct file *f = 0;
@@ -397,7 +401,10 @@ void init_sb(struct super_block *sb, struct vfsmount *vmnt,
 
 /* Dentry Functions */
 
-/* Helper to alloc and initialize a generic dentry.
+/* Helper to alloc and initialize a generic dentry.  The following needs to be
+ * set still: d_op, d_fs_info (opt), d_inode, connect the inode to the dentry
+ * (and up the d_refcnt), maybe dcache_put().  The FS related things need to be
+ * done in fs_create and fs_mkdir.
  *
  * If the name is longer than the inline name, it will kmalloc a buffer, so
  * don't worry about the storage for *name after calling this. */
@@ -440,12 +447,25 @@ struct dentry *get_dentry(struct super_block *sb, struct dentry *parent,
 /* Adds a dentry to the dcache. */
 void dcache_put(struct dentry *dentry)
 {
-       // TODO: prob should do something with the dentry flags
+       /* TODO: should set a d_flag too */
        spin_lock(&dcache_lock);
        SLIST_INSERT_HEAD(&dcache, dentry, d_hash);
        spin_unlock(&dcache_lock);
 }
 
+/* Free the dentry (after ref == 0 and we no longer want it).  Pairs with
+ * get_dentry(), mostly. */
+void free_dentry(struct dentry *dentry)
+{
+       /* Might not have a d_op, if it was involved in a failed operation */
+       if (dentry->d_op && dentry->d_op->d_release)
+               dentry->d_op->d_release(dentry);
+       /* TODO: check/test the boundaries on this. */
+       if (dentry->d_name.len > DNAME_INLINE_LEN)
+               kfree((void*)dentry->d_name.name);
+       kmem_cache_free(dentry_kcache, dentry);
+}
+
 /* Inode Functions */
 
 /* Returns 0 if the given mode is acceptable for the inode, and an appropriate
@@ -557,6 +577,94 @@ ssize_t generic_file_write(struct file *file, const char *buf, size_t count,
        return count;
 }
 
+/* Opens the file, using permissions from current for lack of a better option.
+ * Called by sys_open.  This will return 0 on failure, and set errno.
+ * There's a lot of stuff that we don't do, esp related to permission checking
+ * and file truncating.
+ * TODO: open and create should set errno and propagate it up. */
+struct file *do_file_open(char *path, int flags, int mode)
+{
+       struct file *file = 0;
+       struct dentry *file_d;
+       struct inode *parent_i;
+       struct nameidata nd_r = {0}, *nd = &nd_r;
+       int lookup_flags = LOOKUP_PARENT;
+       int error = 0;
+
+       /* lookup the parent */
+       nd->intent = flags & (O_RDONLY|O_WRONLY|O_RDWR);
+       if (flags & O_CREAT)
+               lookup_flags |= LOOKUP_CREATE;
+       error = path_lookup(path, lookup_flags, nd);
+       if (error) {
+               set_errno(current_tf, -error);
+               return 0;
+       }
+       /* see if the target is there, handle accordingly */
+       file_d = do_lookup(nd->dentry, nd->last.name); 
+       if (!file_d) {
+               if (!(flags & O_CREAT)) {
+                       path_release(nd);
+                       set_errno(current_tf, EACCES);
+                       return 0;
+               }
+               /* Create the inode/file.  get a fresh dentry too: */
+               file_d = get_dentry(nd->dentry->d_sb, nd->dentry, nd->last.name);
+               parent_i = nd->dentry->d_inode;
+               /* TODO: mode should be & ~umask.  Note that mode only applies to future
+                * opens. */
+               if (parent_i->i_op->create(parent_i, file_d, mode, nd)) {
+                       atomic_dec(&file_d->d_refcnt);
+                       free_dentry(file_d); /* TODO: REF trigger off a decref */
+                       set_errno(current_tf, EFAULT);
+                       path_release(nd);
+                       return 0;
+               }
+               /* when we have notions of users, do something here: */
+               file_d->d_inode->i_uid = 0;
+               file_d->d_inode->i_gid = 0;
+               file_d->d_inode->i_flags = flags & ~(O_CREAT|O_TRUNC|O_EXCL|O_NOCTTY);
+               dcache_put(file_d);
+               atomic_dec(&file_d->d_refcnt);  /* TODO: REF / KREF */
+       } else {        /* the file exists */
+               if ((flags & O_CREAT) && (flags & O_EXCL)) {
+                       /* wanted to create, not open */
+                       path_release(nd);
+                       set_errno(current_tf, EACCES);
+                       return 0;
+               }
+       }
+       /* now open the file (freshly created or if it already existed) */
+       file = kmem_cache_alloc(file_kcache, 0);
+       if (!file) {
+               set_errno(current_tf, ENOMEM);
+               path_release(nd);
+               return 0;
+       }
+       if (flags & O_TRUNC)
+               warn("File truncation not supported yet.");
+       if (file_d->d_inode->i_fop->open(file_d->d_inode, file)) {
+               set_errno(current_tf, ENOENT);
+               path_release(nd);
+               kmem_cache_free(file_kcache, file);
+               return 0;
+       }
+       /* TODO: check the inode's mode (S_XXX) against the flags O_RDWR */
+       /* f_mode stores how the FILE is open, regardless of the mode */
+       file->f_mode = flags & (O_RDONLY|O_WRONLY|O_RDWR);
+       path_release(nd);
+       return file;
+}
+
+/* Closes a file, fsync, whatever else is necessary */
+int do_file_close(struct file *file)
+{
+       assert(!file->f_refcnt);
+       /* TODO: fsync */
+       file->f_op->release(file->f_inode, file);
+       return 0;
+}
+
 /* Page cache functions */
 
 /* Looks up the index'th page in the page map, returning an incref'd reference,
@@ -702,24 +810,28 @@ struct file *get_file_from_fd(struct files_struct *open_files, int file_desc)
  * hasn't been thought through yet. */
 struct file *put_file_from_fd(struct files_struct *open_files, int file_desc)
 {
-       struct file *f = 0;
+       struct file *file = 0;
        spin_lock(&open_files->lock);
        if (file_desc < open_files->max_fdset) {
                if (GET_BITMASK_BIT(open_files->open_fds->fds_bits, file_desc)) {
                        /* while max_files and max_fdset might not line up, we should never
                         * have a valid fdset higher than files */
                        assert(file_desc < open_files->max_files);
-                       f = open_files->fd[file_desc];
+                       file = open_files->fd[file_desc];
                        open_files->fd[file_desc] = 0;
+                       CLR_BITMASK_BIT(open_files->open_fds->fds_bits, file_desc);
                        /* TODO: (REF) need to make sure we free if we hit 0 (might do this
                         * in the caller */
-                       if (f)
-                               atomic_dec(&f->f_refcnt);
-                       // if 0, drop, decref from higher, sync, whatever
+                       if (file) {
+                               atomic_dec(&file->f_refcnt);
+                               if (!file->f_refcnt)
+                                       assert(!do_file_close(file));
+                       }
+                       /* the if case is due to files (stdin) without a *file yet */
                }
        }
        spin_unlock(&open_files->lock);
-       return f;
+       return file;
 }
 
 /* Inserts the file in the files_struct, returning the corresponding new file
@@ -745,3 +857,29 @@ int insert_file(struct files_struct *open_files, struct file *file)
        spin_unlock(&open_files->lock);
        return slot;
 }
+
+/* Closes all open files.  Sort of a "put" plus do_file_close(), for all. */
+void close_all_files(struct files_struct *open_files)
+{
+       struct file *file;
+       spin_lock(&open_files->lock);
+       for (int i = 0; i < open_files->max_fdset; i++) {
+               if (GET_BITMASK_BIT(open_files->open_fds->fds_bits, i)) {
+                       /* while max_files and max_fdset might not line up, we should never
+                        * have a valid fdset higher than files */
+                       assert(i < open_files->max_files);
+                       file = open_files->fd[i];
+                       open_files->fd[i] = 0;
+                       /* TODO: we may want to parallelize the blocking... */
+                       if (file) {
+                               /* TODO: REF/KREF */
+                               atomic_dec(&file->f_refcnt);
+                               if (!file->f_refcnt)
+                                       do_file_close(file);
+                       }
+                       /* the if case is due to files (stdin) without a *file yet */
+                       CLR_BITMASK_BIT(open_files->open_fds->fds_bits, i);
+               }
+       }
+       spin_unlock(&open_files->lock);
+}
index 320145d..80be621 100644 (file)
@@ -1,10 +1,18 @@
 #include <stdio.h> 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <arch/arch.h>
+
 int main() 
 { 
        FILE *file; 
-       file = fopen("test.txt","w+b");
+       file = fopen("/dir1/f1.txt","w+b");
        if (file == NULL)
-               printf ("Failed to write to file \n");
+               printf ("Failed to open file \n");
        fprintf(file,"%s","hello, world\n"); 
        fclose(file); 
+
+       int fd = open("/bin/test.txt", O_RDWR | O_CREAT );
+       breakpoint();
 }