Track errno and errstr in the kthread
[akaros.git] / kern / src / vfs.c
index 5005d38..667b52d 100644 (file)
@@ -29,6 +29,32 @@ struct kmem_cache *dentry_kcache; // not to be confused with the dcache
 struct kmem_cache *inode_kcache;
 struct kmem_cache *file_kcache;
 
+enum {
+       VFS_MTIME,
+       VFS_CTIME,
+       VFS_ATIME,
+};
+
+/* mtime implies ctime implies atime. */
+static void set_acmtime(struct inode *inode, int which)
+{
+       struct timespec now = nsec2timespec(epoch_nsec());
+
+       switch (which) {
+       case VFS_MTIME:
+               inode->i_mtime.tv_sec = now.tv_sec;
+               inode->i_mtime.tv_nsec = now.tv_nsec;
+               /* fall through */
+       case VFS_CTIME:
+               inode->i_ctime.tv_sec = now.tv_sec;
+               inode->i_ctime.tv_nsec = now.tv_nsec;
+               /* fall through */
+       case VFS_ATIME:
+               inode->i_atime.tv_sec = now.tv_sec;
+               inode->i_atime.tv_nsec = now.tv_nsec;
+       }
+}
+
 /* Mounts fs from dev_name at mnt_pt in namespace ns.  There could be no mnt_pt,
  * such as with the root of (the default) namespace.  Not sure how it would work
  * with multiple namespaces on the same FS yet.  Note if you mount the same FS
@@ -88,11 +114,14 @@ void vfs_init(void)
        struct fs_type *fs;
 
        dentry_kcache = kmem_cache_create("dentry", sizeof(struct dentry),
-                                         __alignof__(struct dentry), 0, 0, 0);
+                                         __alignof__(struct dentry), 0,
+                                         NULL, 0, 0, NULL);
        inode_kcache = kmem_cache_create("inode", sizeof(struct inode),
-                                        __alignof__(struct inode), 0, 0, 0);
+                                        __alignof__(struct inode), 0, NULL,
+                                        0, 0, NULL);
        file_kcache = kmem_cache_create("file", sizeof(struct file),
-                                       __alignof__(struct file), 0, 0, 0);
+                                       __alignof__(struct file), 0, NULL, 0,
+                                       0, NULL);
        /* default NS never dies, +1 to exist */
        kref_init(&default_ns.kref, fake_release, 1);
        spinlock_init(&default_ns.lock);
@@ -1023,7 +1052,6 @@ void load_inode(struct dentry *dentry, unsigned long ino)
  * note we don't pass this an nd, like Linux does... */
 static struct inode *create_inode(struct dentry *dentry, int mode)
 {
-       struct timespec now = nsec2timespec(epoch_nsec());
        /* note it is the i_ino that uniquely identifies a file in the specific
         * filesystem.  there's a diff between creating an inode (even for an in-use
         * ino) and then filling it in, and vs creating a brand new one.
@@ -1036,12 +1064,7 @@ static struct inode *create_inode(struct dentry *dentry, int mode)
        inode->i_nlink = 1;
        inode->i_size = 0;
        inode->i_blocks = 0;
-       inode->i_atime.tv_sec = now.tv_sec;
-       inode->i_ctime.tv_sec = now.tv_sec;
-       inode->i_mtime.tv_sec = now.tv_sec;
-       inode->i_atime.tv_nsec = now.tv_nsec;
-       inode->i_ctime.tv_nsec = now.tv_nsec;
-       inode->i_mtime.tv_nsec = now.tv_nsec;
+       set_acmtime(inode, VFS_MTIME);
        inode->i_bdev = inode->i_sb->s_bdev;
        /* when we have notions of users, do something here: */
        inode->i_uid = 0;
@@ -1058,6 +1081,7 @@ int create_file(struct inode *dir, struct dentry *dentry, int mode)
        if (!new_file)
                return -1;
        dir->i_op->create(dir, dentry, mode, 0);
+       set_acmtime(dir, VFS_MTIME);
        icache_put(new_file->i_sb, new_file);
        kref_put(&new_file->i_kref);
        return 0;
@@ -1078,6 +1102,7 @@ int create_dir(struct inode *dir, struct dentry *dentry, int mode)
        assert(parent && parent == TAILQ_LAST(&dir->i_dentry, dentry_tailq));
        /* parent dentry tracks dentry as a subdir, weak reference */
        TAILQ_INSERT_TAIL(&parent->d_subdirs, dentry, d_subdirs_link);
+       set_acmtime(dir, VFS_MTIME);
        icache_put(new_dir->i_sb, new_dir);
        kref_put(&new_dir->i_kref);
        return 0;
@@ -1092,6 +1117,7 @@ int create_symlink(struct inode *dir, struct dentry *dentry,
        if (!new_sym)
                return -1;
        dir->i_op->symlink(dir, dentry, symname);
+       set_acmtime(dir, VFS_MTIME);
        icache_put(new_sym->i_sb, new_sym);
        kref_put(&new_sym->i_kref);
        return 0;
@@ -1265,6 +1291,7 @@ ssize_t generic_file_read(struct file *file, char *buf, size_t count,
         * safe.  but at least it'll be a value that one of the concurrent ops could
         * have produced (compared to *offset_changed_concurrently += count. */
        *offset = orig_off + count;
+       set_acmtime(file->f_dentry->d_inode, VFS_ATIME);
        return count;
 }
 
@@ -1331,6 +1358,7 @@ ssize_t generic_file_write(struct file *file, const char *buf, size_t count,
        }
        assert(buf == buf_end);
        *offset = orig_off + count;
+       set_acmtime(file->f_dentry->d_inode, VFS_MTIME);
        return count;
 }
 
@@ -1384,6 +1412,7 @@ ssize_t generic_dir_read(struct file *file, char *u_buf, size_t count,
        /* important to tell them how much they got.  they often keep going til they
         * get 0 back (in the case of ls).  It's also how much has been read, but it
         * isn't how much the f_pos has moved (which is opaque to the VFS). */
+       set_acmtime(file->f_dentry->d_inode, VFS_ATIME);
        return amt_copied;
 }
 
@@ -1517,6 +1546,7 @@ int do_symlink(char *path, const char *symname, int mode)
        parent_i = nd->dentry->d_inode;
        if (create_symlink(parent_i, sym_d, symname, mode))
                goto out_sym_d;
+       set_acmtime(parent_i, VFS_MTIME);
        dcache_put(sym_d->d_sb, sym_d);
        retval = 0;                             /* Note the fall through to the exit paths */
 out_sym_d:
@@ -1575,6 +1605,7 @@ int do_link(char *old_path, char *new_path)
                set_errno(-error);
                goto out_both_ds;
        }
+       set_acmtime(parent_dir, VFS_MTIME);
        /* Finally stitch it up */
        inode = old_d->d_inode;
        kref_get(&inode->i_kref, 1);
@@ -1626,6 +1657,7 @@ int do_unlink(char *path)
                set_errno(-error);
                goto out_dentry;
        }
+       set_acmtime(parent_dir, VFS_MTIME);
        /* Now that our parent doesn't track us, we need to make sure we aren't
         * findable via the dentry cache.  DYING, so we will be freed in
         * dentry_release() */
@@ -1668,6 +1700,7 @@ int do_file_chmod(struct file *file, int mode)
        else
        #endif
                file->f_dentry->d_inode->i_mode = (mode & S_PMASK) | old_mode_ftype;
+       set_acmtime(file->f_dentry->d_inode, VFS_CTIME);
        return 0;
 }
 
@@ -1702,6 +1735,7 @@ int do_mkdir(char *path, int mode)
        parent_i = nd->dentry->d_inode;
        if (create_dir(parent_i, dentry, mode))
                goto out_dentry;
+       set_acmtime(parent_i, VFS_MTIME);
        dcache_put(dentry->d_sb, dentry);
        retval = 0;                             /* Note the fall through to the exit paths */
 out_dentry:
@@ -1751,6 +1785,7 @@ int do_rmdir(char *path)
                set_errno(-error);
                goto out_dentry;
        }
+       set_acmtime(parent_i, VFS_MTIME);
        /* Now that our parent doesn't track us, we need to make sure we aren't
         * findable via the dentry cache.  DYING, so we will be freed in
         * dentry_release() */
@@ -1847,6 +1882,7 @@ ssize_t pipe_file_read(struct file *file, char *buf, size_t count,
        if (amt_copied)
                __cv_broadcast(&pii->p_cv);
        cv_unlock(&pii->p_cv);
+       set_acmtime(file->f_dentry->d_inode, VFS_ATIME);
        return amt_copied;
 }
 
@@ -1901,6 +1937,7 @@ ssize_t pipe_file_write(struct file *file, const char *buf, size_t count,
        if (amt_copied)
                __cv_broadcast(&pii->p_cv);
        cv_unlock(&pii->p_cv);
+       set_acmtime(file->f_dentry->d_inode, VFS_MTIME);
        return amt_copied;
 }
 
@@ -2057,7 +2094,6 @@ int do_rename(char *old_path, char *new_path)
        struct dentry *old_d, *new_d, *unlink_d;
        int error;
        int retval = 0;
-       struct timespec now;
 
        nd_o->intent = LOOKUP_ACCESS; /* maybe, might need another type */
 
@@ -2185,16 +2221,9 @@ int do_rename(char *old_path, char *new_path)
         * replace a potentially negative dentry for new_d (now called old_d) */
        dcache_put(old_dir_d->d_sb, old_d);
 
-       /* TODO could have a helper for this, but it's going away soon */
-       now = nsec2timespec(epoch_nsec());
-       old_dir_i->i_ctime.tv_sec = now.tv_sec;
-       old_dir_i->i_mtime.tv_sec = now.tv_sec;
-       old_dir_i->i_ctime.tv_nsec = now.tv_nsec;
-       old_dir_i->i_mtime.tv_nsec = now.tv_nsec;
-       new_dir_i->i_ctime.tv_sec = now.tv_sec;
-       new_dir_i->i_mtime.tv_sec = now.tv_sec;
-       new_dir_i->i_ctime.tv_nsec = now.tv_nsec;
-       new_dir_i->i_mtime.tv_nsec = now.tv_nsec;
+       set_acmtime(old_dir_i, VFS_MTIME);
+       set_acmtime(new_dir_i, VFS_MTIME);
+       set_acmtime(old_d->d_inode, VFS_CTIME);
 
        /* fall-through */
 out_paths_and_refs:
@@ -2211,7 +2240,7 @@ out_old_path:
 int do_truncate(struct inode *inode, off64_t len)
 {
        off64_t old_len;
-       struct timespec now;
+
        if (len < 0) {
                set_errno(EINVAL);
                return -1;
@@ -2236,11 +2265,7 @@ int do_truncate(struct inode *inode, off64_t len)
                pm_remove_contig(inode->i_mapping, old_len >> PGSHIFT,
                                 (len >> PGSHIFT) - (old_len >> PGSHIFT));
        }
-       now = nsec2timespec(epoch_nsec());
-       inode->i_ctime.tv_sec = now.tv_sec;
-       inode->i_mtime.tv_sec = now.tv_sec;
-       inode->i_ctime.tv_nsec = now.tv_nsec;
-       inode->i_mtime.tv_nsec = now.tv_nsec;
+       set_acmtime(inode, VFS_MTIME);
        return 0;
 }