Block extra_data
[akaros.git] / kern / src / vfs.c
index 38928d7..d5f45a7 100644 (file)
@@ -715,7 +715,7 @@ void dentry_release(struct kref *kref)
 void __dentry_free(struct dentry *dentry)
 {
        if (dentry->d_inode)
-               printk("Freeing dentry %p: %s\n", dentry, dentry->d_name.name);
+               printd("Freeing dentry %p: %s\n", dentry, dentry->d_name.name);
        assert(dentry->d_op);   /* catch bugs.  a while back, some lacked d_op */
        dentry->d_op->d_release(dentry);
        /* TODO: check/test the boundaries on this. */
@@ -1084,6 +1084,24 @@ void stat_inode(struct inode *inode, struct kstat *kstat)
        kstat->st_ctime = inode->i_ctime;
 }
 
+void print_kstat(struct kstat *kstat)
+{
+       printk("kstat info for %p:\n", kstat);
+       printk("\tst_dev    : %p\n", kstat->st_dev);
+       printk("\tst_ino    : %p\n", kstat->st_ino);
+       printk("\tst_mode   : %p\n", kstat->st_mode);
+       printk("\tst_nlink  : %p\n", kstat->st_nlink);
+       printk("\tst_uid    : %p\n", kstat->st_uid);
+       printk("\tst_gid    : %p\n", kstat->st_gid);
+       printk("\tst_rdev   : %p\n", kstat->st_rdev);
+       printk("\tst_size   : %p\n", kstat->st_size);
+       printk("\tst_blksize: %p\n", kstat->st_blksize);
+       printk("\tst_blocks : %p\n", kstat->st_blocks);
+       printk("\tst_atime  : %p\n", kstat->st_atime);
+       printk("\tst_mtime  : %p\n", kstat->st_mtime);
+       printk("\tst_ctime  : %p\n", kstat->st_ctime);
+}
+
 /* Inode Cache management.  In general, search on the ino, get a refcnt'd value
  * back.  Remove does not give you a reference back - it should only be called
  * in inode_release(). */
@@ -2040,6 +2058,52 @@ struct file *get_file_from_fd(struct files_struct *open_files, int file_desc)
        return retval;
 }
 
+/* Grow the vfs fd set */
+static int grow_fd_set(struct files_struct *open_files) {
+       int n;
+       struct file_desc *nfd, *ofd;
+
+       /* Only update open_fds once. If currently pointing to open_fds_init, then
+        * update it to point to a newly allocated fd_set with space for
+        * NR_FILE_DESC_MAX */
+       if (open_files->open_fds == (struct fd_set*)&open_files->open_fds_init) {
+               open_files->open_fds = kzmalloc(sizeof(struct fd_set), 0);
+               memmove(open_files->open_fds, &open_files->open_fds_init,
+                       sizeof(struct small_fd_set));
+       }
+
+       /* Grow the open_files->fd array in increments of NR_OPEN_FILES_DEFAULT */
+       n = open_files->max_files + NR_OPEN_FILES_DEFAULT;
+       if (n > NR_FILE_DESC_MAX)
+               n = NR_FILE_DESC_MAX;
+       nfd = kzmalloc(n * sizeof(struct file_desc), 0);
+       if (nfd == NULL)
+               return -1;
+
+       /* Move the old array on top of the new one */
+       ofd = open_files->fd;
+       memmove(nfd, ofd, open_files->max_files * sizeof(struct file_desc));
+
+       /* Update the array and the maxes for both max_files and max_fdset */
+       open_files->fd = nfd;
+       open_files->max_files = n;
+       open_files->max_fdset = n;
+
+       /* Only free the old one if it wasn't pointing to open_files->fd_array */
+       if (ofd != open_files->fd_array)
+               kfree(ofd);
+       return 0;
+}
+
+/* Free the vfs fd set if necessary */
+static void free_fd_set(struct files_struct *open_files) {
+       if (open_files->open_fds != (struct fd_set*)&open_files->open_fds_init) {
+               kfree(open_files->open_fds);
+               assert(open_files->fd != open_files->fd_array);
+               kfree(open_files->fd);
+       }
+}
+
 /* 9ns: puts back an FD from the VFS-FD-space. */
 int put_fd(struct files_struct *open_files, int file_desc)
 {
@@ -2076,7 +2140,7 @@ 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].fd_file;
                        open_files->fd[file_desc].fd_file = 0;
-                       assert(file);
+                       assert(file);   /* 9ns shouldn't call this put */
                        kref_put(&file->f_kref);
                        CLR_BITMASK_BIT(open_files->open_fds->fds_bits, file_desc);
                }
@@ -2092,19 +2156,28 @@ static int __get_fd(struct files_struct *open_files, int low_fd)
                return -EINVAL;
        if (open_files->closed)
                return -EINVAL; /* won't matter, they are dying */
-       for (int i = low_fd; i < open_files->max_fdset; i++) {
-               if (GET_BITMASK_BIT(open_files->open_fds->fds_bits, i))
-                       continue;
-               slot = i;
-               SET_BITMASK_BIT(open_files->open_fds->fds_bits, slot);
-               assert(slot < open_files->max_files &&
-                      open_files->fd[slot].fd_file == 0);
-               if (slot >= open_files->next_fd)
-                       open_files->next_fd = slot + 1;
-               break;
-       }
-       if (slot == -1) /* should expand the FD array and fd_set */
-               warn("Ran out of file descriptors, deal with me!");
+
+       /* Loop until we have a valid slot (we grow the fd_array at the bottom of
+        * the loop if we haven't found a slot in the current array */
+       while (slot == -1) {
+               for (low_fd; low_fd < open_files->max_fdset; low_fd++) {
+                       if (GET_BITMASK_BIT(open_files->open_fds->fds_bits, low_fd))
+                               continue;
+                       slot = low_fd;
+                       SET_BITMASK_BIT(open_files->open_fds->fds_bits, slot);
+                       assert(slot < open_files->max_files &&
+                              open_files->fd[slot].fd_file == 0);
+                       if (slot >= open_files->next_fd)
+                               open_files->next_fd = slot + 1;
+                       break;
+               }
+               if (slot == -1) {
+                       /* Expand the FD array and fd_set */
+                       if (grow_fd_set(open_files) == -1)
+                               return -ENOMEM;
+                       /* loop after growing */
+               }
+       }
        return slot;
 }
 
@@ -2118,6 +2191,40 @@ int get_fd(struct files_struct *open_files, int low_fd)
        return slot;
 }
 
+static int __claim_fd(struct files_struct *open_files, int file_desc)
+{
+       if ((file_desc < 0) || (file_desc > NR_FILE_DESC_MAX))
+               return -EINVAL;
+       if (open_files->closed)
+               return -EINVAL; /* won't matter, they are dying */
+
+       /* Grow the open_files->fd_set until the file_desc can fit inside it */
+       while(file_desc >= open_files->max_files) {
+               grow_fd_set(open_files);
+               cpu_relax();
+       }
+
+       /* If we haven't grown, this could be a problem, so check for it */
+       if (GET_BITMASK_BIT(open_files->open_fds->fds_bits, file_desc))
+               return -ENFILE; /* Should never really happen. Here to catch bugs. */
+
+       SET_BITMASK_BIT(open_files->open_fds->fds_bits, file_desc);
+       assert(file_desc < open_files->max_files && open_files->fd[0].fd_file == 0);
+       if (file_desc >= open_files->next_fd)
+               open_files->next_fd = file_desc + 1;
+       return 0;
+}
+
+/* Claims a specific FD when duping FDs. used by 9ns.  < 0 == error. */
+int claim_fd(struct files_struct *open_files, int file_desc)
+{
+       int ret;
+       spin_lock(&open_files->lock);
+       ret = __claim_fd(open_files, file_desc);
+       spin_unlock(&open_files->lock);
+       return ret;
+}
+
 /* Inserts the file in the files_struct, returning the corresponding new file
  * descriptor, or an error code.  We start looking for open fds from low_fd. */
 int insert_file(struct files_struct *open_files, struct file *file, int low_fd)
@@ -2148,8 +2255,6 @@ void close_all_files(struct files_struct *open_files, bool cloexec)
                spin_unlock(&open_files->lock);
                return;
        }
-       if (!cloexec)
-               open_files->closed = TRUE;
        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
@@ -2168,6 +2273,10 @@ void close_all_files(struct files_struct *open_files, bool cloexec)
                        CLR_BITMASK_BIT(open_files->open_fds->fds_bits, i);
                }
        }
+       if (!cloexec) {
+               free_fd_set(open_files);
+               open_files->closed = TRUE;
+       }
        spin_unlock(&open_files->lock);
 }
 
@@ -2196,8 +2305,9 @@ void clone_files(struct files_struct *src, struct files_struct *dst)
                        assert(i < dst->max_files && dst->fd[i].fd_file == 0);
                        SET_BITMASK_BIT(dst->open_fds->fds_bits, i);
                        dst->fd[i].fd_file = file;
-                       assert(file);
-                       kref_get(&file->f_kref, 1);
+                       /* no file means 9ns is using it, they clone separately */
+                       if (file)
+                               kref_get(&file->f_kref, 1);
                        if (i >= dst->next_fd)
                                dst->next_fd = i + 1;
                }