sys_chdir()
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 19 Aug 2010 21:53:56 +0000 (14:53 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:52 +0000 (17:35 -0700)
Also fixes up some dentry refcounting issues.

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

index bbd78f6..d6b4a0d 100644 (file)
@@ -522,6 +522,7 @@ 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, bool cloexec);
 void clone_files(struct files_struct *src, struct files_struct *dst);
+int do_chdir(struct fs_struct *fs_env, char *path);
 
 /* Debugging */
 int ls_dash_r(char *path);
index 2030349..a5e900a 100644 (file)
@@ -384,6 +384,8 @@ static void __proc_free(struct kref *kref)
        assert(kref_refcnt(&p->kref) == 0);
 
        close_all_files(&p->open_files, FALSE);
+       kref_put(&p->fs_env.root->d_kref);
+       kref_put(&p->fs_env.pwd->d_kref);
        destroy_vmrs(p);
        frontend_proc_free(p);  /* TODO: please remove me one day */
        /* Free any colors allocated to this process */
index 5c74c1b..baa8edf 100644 (file)
@@ -1091,12 +1091,17 @@ intreg_t sys_readlink(struct proc *p, char *path, size_t path_l,
 
 intreg_t sys_chdir(struct proc *p, const char *path, size_t path_l)
 {
-       char* fn = user_strdup_errno(p,path,PGSIZE);
-       if(fn == NULL)
+       int retval;
+       char *t_path = user_strdup_errno(p, path, path_l);
+       if (!t_path)
                return -1;
-       int ret = ufe(chdir,PADDR(fn),0,0,0);
-       user_memdup_free(p,fn);
-       return ret;
+       retval = do_chdir(&p->fs_env, t_path);
+       user_memdup_free(p, t_path);
+       if (retval) {
+               set_errno(-retval);
+               return -1;
+       }
+       return 0;
 }
 
 intreg_t sys_getcwd(struct proc *p, char *pwd, int size)
index d3334bc..18052f9 100644 (file)
@@ -591,11 +591,13 @@ void dentry_release(struct kref *kref)
        if (dentry->d_name.len > DNAME_INLINE_LEN)
                kfree((void*)dentry->d_name.name);
        kref_put(&dentry->d_sb->s_kref);
+       if (dentry->d_parent)
+               kref_put(&dentry->d_parent->d_kref);
        if (dentry->d_mounted_fs)
                kref_put(&dentry->d_mounted_fs->mnt_kref);
        if (dentry->d_inode) {
                TAILQ_REMOVE(&dentry->d_inode->i_dentry, dentry, d_alias);
-               kref_put(&dentry->d_inode->i_kref);     /* but dentries kref inodes */
+               kref_put(&dentry->d_inode->i_kref);     /* dentries kref inodes */
        }
        kmem_cache_free(dentry_kcache, dentry);
 }
@@ -1495,6 +1497,23 @@ void clone_files(struct files_struct *src, struct files_struct *dst)
        spin_unlock(&src->lock);
 }
 
+/* Change the working directory of the given fs env (one per process, at this
+ * point).  Returns 0 for success, -ERROR for whatever error. */
+int do_chdir(struct fs_struct *fs_env, char *path)
+{
+       struct nameidata nd_r = {0}, *nd = &nd_r;
+       int retval;
+       retval = path_lookup(path, LOOKUP_DIRECTORY, nd);
+       if (!retval) {
+               /* nd->dentry is the place we want our PWD to be */
+               kref_get(&nd->dentry->d_kref, 1);
+               kref_put(&fs_env->pwd->d_kref);
+               fs_env->pwd = nd->dentry;
+       }
+       path_release(nd);
+       return retval;
+}
+
 static void print_dir(struct dentry *dentry, char *buf, int depth)
 {
        struct dentry *child_d;
index 5ddd81c..a22751e 100644 (file)
@@ -40,6 +40,7 @@ int main()
        //retval = stat("/bin/mhello", &st);
        retval = fstat(fd, &st);
        printf("Tried to stat, was told %d\n", retval);
+       #if 0
        printf("STAT RESULTS\n---------------------\n");
        printf("dev       : %d\n", st.st_dev);
        printf("ino       : %d\n", st.st_ino);
@@ -54,6 +55,7 @@ int main()
        printf("atime     : %d\n", st.st_atime);
        printf("mtime     : %d\n", st.st_mtime);
        printf("ctime     : %d\n", st.st_ctime);
+       #endif
 
        retval = symlink("/dir1/random.txt", "/dir2/sym-test");
        if (retval < 0)
@@ -116,5 +118,18 @@ int main()
        retval = unlink("/dir2/test2.txt");
        if (retval < 0)
                printf("WARNING! Unlink failed!\n");
+
+       /* chdir() tests */
+       printf("Testing basic chdir\n");
+       retval = access("dir1/f1.txt", R_OK);
+       if (retval < 0)
+               printf("WARNING! Access error for dir1/f1.txt!\n");
+       retval = chdir("/dir1");
+       if (retval < 0)
+               printf("WARNING! Chdir failed for /dir1!\n");
+       retval = access("f1.txt", R_OK);
+       if (retval < 0)
+               printf("WARNING! Access error for f1.txt!\n");
+
        breakpoint();
 }