parlib: Expand our printf hacks
[akaros.git] / kern / src / kfs.c
index e36175f..eef0470 100644 (file)
@@ -5,15 +5,6 @@
  * Implementation of the KFS file system.  It is a RAM based, read-only FS
  * consisting of files that are added to the kernel binary image.  Might turn
  * this into a read/write FS with directories someday. */
-
-#ifdef __SHARC__
-#pragma nosharc
-#endif
-
-#ifdef __DEPUTY__
-#pragma nodeputy
-#endif
-
 #include <vfs.h>
 #include <kfs.h>
 #include <slab.h>
@@ -56,11 +47,13 @@ struct kmem_cache *kfs_i_kcache;
 
 static void kfs_init(void)
 {
-       kfs_i_kcache = kmem_cache_create("kfs_ino_info", sizeof(struct kfs_i_info),
-                                        __alignof__(struct kfs_i_info), 0, 0, 0);
+       kfs_i_kcache = kmem_cache_create("kfs_ino_info",
+                                        sizeof(struct kfs_i_info),
+                                        __alignof__(struct kfs_i_info), 0,
+                                        NULL, 0, 0, NULL);
 }
 
-/* Creates the SB (normally would read in from disc and create).  Passes it's
+/* Creates the SB (normally would read in from disc and create).  Passes its
  * ref out to whoever consumes this.  Returns 0 on failure.
  * TODO: consider pulling out more of the FS-independent stuff, if possible.
  * There are only two things, but the pain in the ass is that you'd need to read
@@ -125,6 +118,12 @@ int kfs_readpage(struct page_map *pm, struct page *page)
        struct kfs_i_info *k_i_info = (struct kfs_i_info*)
                                      pm->pm_host->i_fs_info;
        uintptr_t begin = (size_t)k_i_info->filestart + pg_idx_byte;
+
+       /* Pretend that we blocked while filing this page.  This catches a lot of
+        * bugs.  It does slightly slow down the kernel, but it's only when filling
+        * the page cache, and considering we are using a RAMFS, you shouldn't
+        * measure things that actually rely on KFS's performance. */
+       kthread_usleep(1);
        /* If we're beyond the initial start point, we just need a zero page.  This
         * is for a hole or for extending a file (even though it won't be saved).
         * Otherwise, we want the data from KFS, being careful to not copy from
@@ -158,6 +157,7 @@ int kfs_readpage(struct page_map *pm, struct page *page)
 
 int kfs_writepage(struct page_map *pm, struct page *page)
 {
+       warn_once("KFS writepage does not save file contents!\n");
        return -1;
 }
 
@@ -400,8 +400,7 @@ int kfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
        kfs_init_inode(dir, dentry);
        SET_FTYPE(inode->i_mode, __S_IFLNK);
        inode->i_fop = &kfs_f_op_sym;
-       strncpy(string, symname, len);
-       string[len] = '\0';             /* symname should be \0d anyway, but just in case */
+       strlcpy(string, symname, len + 1);
        k_i_info->filestart = string;   /* reusing this void* to hold the char* */
        return 0;
 }
@@ -444,7 +443,7 @@ int kfs_rmdir(struct inode *dir, struct dentry *dentry)
        if (!empty)
                return -ENOTEMPTY;
        kref_put(&dentry->d_kref);                              /* unpin the dentry, KFS-style */
-       printk("DENTRY %s REFCNT %d\n", dentry->d_name.name, kref_refcnt(&dentry->d_kref));
+       printd("DENTRY %s REFCNT %d\n", dentry->d_name.name, kref_refcnt(&dentry->d_kref));
        return 0;
 }
 
@@ -456,11 +455,26 @@ int kfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
        return -1;
 }
 
-/* Moves old_dentry from old_dir to new_dentry in new_dir */
-int kfs_rename(struct inode *old_dir, struct dentry *old_dentry,
-               struct inode *new_dir, struct dentry *new_dentry)
-{
-       return -1;
+/* Moves old_d from old_dir to new_d in new_dir.  TODO: super racy */
+int kfs_rename(struct inode *old_dir, struct dentry *old_d,
+               struct inode *new_dir, struct dentry *new_d)
+{
+       /* new_d is already gone, we just use it for its name.  kfs might not care
+        * about the name.  it might just use whatever the dentry says. */
+       struct kfs_i_info *old_info = (struct kfs_i_info*)old_dir->i_fs_info;
+       struct kfs_i_info *new_info = (struct kfs_i_info*)new_dir->i_fs_info;
+       printd("KFS rename: %s/%s -> %s/%s\n",
+              TAILQ_FIRST(&old_dir->i_dentry)->d_name.name, old_d->d_name.name,
+              TAILQ_FIRST(&new_dir->i_dentry)->d_name.name, new_d->d_name.name);
+       /* we want to remove from the old and add to the new.  for non-directories,
+        * we need to adjust parent's children lists (which reuses subdirs_link,
+        * yikes!).  directories aren't actually tracked by KFS; it just hopes the
+        * VFS's pinned dentry tree is enough (aka, "all paths pinned"). */
+       if (!S_ISDIR(old_d->d_inode->i_mode)) {
+               TAILQ_REMOVE(&old_info->children, old_d, d_subdirs_link);
+               TAILQ_INSERT_TAIL(&new_info->children, old_d, d_subdirs_link);
+       }
+       return 0;
 }
 
 /* Returns the char* for the symname for the given dentry.  The VFS code that
@@ -480,6 +494,11 @@ char *kfs_readlink(struct dentry *dentry)
 /* Modifies the size of the file of inode to whatever its i_size is set to */
 void kfs_truncate(struct inode *inode)
 {
+       struct kfs_i_info *k_i_info = (struct kfs_i_info*)inode->i_fs_info;
+       /* init_size tracks how much of the file KFS has.  everything else is 0s.
+        * we only need to update it if we are dropping data.  as with other data
+        * beyond init_size, KFS will not save it during a write page! */
+       k_i_info->init_size = MIN(k_i_info->init_size, inode->i_size);
 }
 
 /* Checks whether the the access mode is allowed for the file belonging to the
@@ -498,12 +517,6 @@ int kfs_d_revalidate(struct dentry *dir, struct nameidata *nd)
        return -1;
 }
 
-/* Produces the hash to lookup this dentry from the dcache */
-int kfs_d_hash(struct dentry *dentry, struct qstr *name)
-{
-       return -1;
-}
-
 /* Compares name1 and name2.  name1 should be a member of dir. */
 int kfs_d_compare(struct dentry *dir, struct qstr *name1, struct qstr *name2)
 { // default, string comp (case sensitive)
@@ -522,7 +535,7 @@ int kfs_d_release(struct dentry *dentry)
        return -1;
 }
 
-/* Called when the dentry loses it's inode (becomes "negative") */
+/* Called when the dentry loses its inode (becomes "negative") */
 void kfs_d_iput(struct dentry *dentry, struct inode *inode)
 { // default, call i_put to release the inode object
 }
@@ -530,8 +543,7 @@ void kfs_d_iput(struct dentry *dentry, struct inode *inode)
 
 /* file_operations */
 
-/* Updates the file pointer.  KFS doesn't let you go past the end of a file
- * yet, so it won't let you seek past either.  TODO: think about locking. */
+/* Updates the file pointer.  TODO: think about locking. */
 int kfs_llseek(struct file *file, off64_t offset, off64_t *ret, int whence)
 {
        off64_t temp_off = 0;
@@ -550,9 +562,6 @@ int kfs_llseek(struct file *file, off64_t offset, off64_t *ret, int whence)
                        warn("Unknown 'whence' in llseek()!\n");
                        return -1;
        }
-       /* make sure the f_pos isn't outside the limits of the existing file.
-        * techincally, if they go too far, we should return EINVAL */
-       temp_off = MAX(MIN(temp_off, file->f_dentry->d_inode->i_size), 0);
        file->f_pos = temp_off;
        *ret = temp_off;
        return 0;
@@ -582,9 +591,14 @@ int kfs_readdir(struct file *dir, struct dirent *dirent)
                        dirent->d_ino = subent->d_inode->i_ino;
                        dirent->d_off = count;
                        dirent->d_reclen = subent->d_name.len;
-                       /* d_name.name is null terminated, the byte after d_name.len */
-                       assert(subent->d_name.len <= MAX_FILENAME_SZ);
-                       strncpy(dirent->d_name, subent->d_name.name, subent->d_name.len +1);
+                       /* d_name.name is null terminated, the byte after d_name.len.
+                        * Regardless, exercise caution as we copy into d_name, should
+                        * the size of the quickstring buffer and the size of d_name
+                        * fall out of sync with one another. */
+                       assert(subent->d_name.len < sizeof(dirent->d_name));
+                       strncpy(dirent->d_name, subent->d_name.name,
+                               sizeof(dirent->d_name) - 1);
+                       dirent->d_name[sizeof(dirent->d_name) - 1] = '\0';
                        found = TRUE;
                }
        }
@@ -594,13 +608,13 @@ int kfs_readdir(struct file *dir, struct dirent *dirent)
                dirent->d_ino = dir_d->d_inode->i_ino;
                dirent->d_off = 1;
                dirent->d_reclen = 1;
-               strncpy(dirent->d_name, ".", 2);        /* the extra is for the null term */
+               strlcpy(dirent->d_name, ".", sizeof(dirent->d_name));
                found = TRUE;
        } else if (desired_file == 1) {
                dirent->d_ino = dir_d->d_parent->d_inode->i_ino;
                dirent->d_off = 2;
                dirent->d_reclen = 2;
-               strncpy(dirent->d_name, "..", 3);       /* the extra is for the null term */
+               strlcpy(dirent->d_name, "..", sizeof(dirent->d_name));
                found = TRUE;
        }
        /* need to check the sub-dirs as well as the sub-"files".  The main
@@ -730,7 +744,7 @@ struct inode_operations kfs_i_op = {
 
 struct dentry_operations kfs_d_op = {
        kfs_d_revalidate,
-       kfs_d_hash,
+       generic_dentry_hash,
        kfs_d_compare,
        kfs_d_delete,
        kfs_d_release,
@@ -797,7 +811,7 @@ struct file_operations kfs_f_op_sym = {
 static int __add_kfs_entry(struct dentry *parent, char *path,
                            struct cpio_bin_hdr *c_bhdr)
 {
-       char *first_slash = strchr(path, '/');  
+       char *first_slash = strchr(path, '/');
        char dir[MAX_FILENAME_SZ + 1];  /* room for the \0 */
        size_t dirname_sz;                              /* not counting the \0 */
        struct dentry *dentry = 0;
@@ -811,7 +825,7 @@ static int __add_kfs_entry(struct dentry *parent, char *path,
                 * anything like that. */
                dirname_sz = first_slash - path;
                assert(dirname_sz <= MAX_FILENAME_SZ);
-               strncpy(dir, path, dirname_sz);
+               memmove(dir, path, dirname_sz);
                dir[dirname_sz] = '\0';
                printd("Finding DIR %s in dentry %s (start: %p, size %d)\n", dir,
                       parent->d_name.name, c_bhdr->c_filestart, c_bhdr->c_filesize);