9ns: Implement chdir/fchdir
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 6 Mar 2018 19:20:55 +0000 (11:20 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 30 Apr 2018 18:31:44 +0000 (14:31 -0400)
You won't be able to use it easily, since the VFS will still get first
dibs on lookups.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/ns.h
kern/src/ns/pgrp.c
kern/src/ns/sysfile.c
kern/src/syscall.c

index f3fecdf..822cde1 100644 (file)
@@ -611,8 +611,6 @@ struct pgrp {
        qlock_t nsh;
        struct mhead *mnthash[MNTHASH];
        int progmode;
-       struct chan *dot;
-       struct chan *slash;
        int nodevs;
        int pin;
 };
@@ -1005,6 +1003,7 @@ long kchanio(void *vc, void *buf, int n, int mode);
 int openmode(uint32_t o);
 void fdclose(struct fd_table *fdt, int fd);
 int syschdir(char *path);
+int sysfchdir(int fd);
 int grpclose(struct fd_table *fdt, int fd);
 int sysclose(int fd);
 int syscreate(char *path, int mode, uint32_t perm);
index df747d5..f06b1bf 100644 (file)
@@ -65,8 +65,6 @@ void closepgrp(struct pgrp *p)
                }
        }
        wunlock(&p->ns);
-       cclose(p->dot);
-       cclose(p->slash);
        kfree(p);
 }
 
@@ -161,8 +159,6 @@ void pgrpcpy(struct pgrp *to, struct pgrp *from)
        }
 
        to->progmode = from->progmode;
-       to->slash = cclone(from->slash);
-       to->dot = cclone(from->dot);
        to->nodevs = from->nodevs;
 
        poperror();
index 3922b34..ea7a4c6 100644 (file)
@@ -39,6 +39,7 @@
 #include <pmap.h>
 #include <smp.h>
 #include <net/ip.h>
+#include <rcu.h>
 
 /* TODO: these sizes are hokey.  DIRSIZE is used in chandirstat, and it looks
  * like it's the size of a common-case stat. */
@@ -145,22 +146,40 @@ void fdclose(struct fd_table *fdt, int fd)
        close_fd(fdt, fd);
 }
 
+static void set_dot(struct chan *c)
+{
+       c = atomic_swap_ptr((void**)&current->dot, c);
+       synchronize_rcu();
+       cclose(c);
+}
+
 int syschdir(char *path)
 {
        ERRSTACK(1);
        struct chan *c;
-       struct pgrp *pg;
 
        if (waserror()) {
                poperror();
                return -1;
        }
-
        c = namec(path, Atodir, 0, 0, NULL);
-       pg = current->pgrp;
-       cclose(pg->dot);
-       pg->dot = c;
        poperror();
+       set_dot(c);
+       return 0;
+}
+
+int sysfchdir(int fd)
+{
+       ERRSTACK(1);
+       struct chan *c;
+
+       if (waserror()) {
+               poperror();
+               return -1;
+       }
+       c = fdtochan(&current->open_files, fd, -1, 0, 1);
+       poperror();
+       set_dot(c);
        return 0;
 }
 
@@ -1329,7 +1348,8 @@ void print_chaninfo(struct chan *c)
 int plan9setup(struct proc *new_proc, struct proc *parent, int flags)
 {
 
-       struct kref *new_dot_ref;
+       struct chan *new_dot;
+
        ERRSTACK(1);
        if (waserror()) {
                printk("plan9setup failed, %s\n", current_errstr());
@@ -1357,14 +1377,13 @@ int plan9setup(struct proc *new_proc, struct proc *parent, int flags)
        /* / should never disappear while we hold a ref to parent */
        chan_incref(parent->slash);
        new_proc->slash = parent->slash;
-       /* dot could change concurrently, and we could fail to gain a ref if whoever
-        * decref'd dot triggered the release.  if that did happen, new_proc->dot
-        * should update and we can try again. */
-       while (!(new_dot_ref = kref_get_not_zero(&parent->dot->ref, 1)))
-               cpu_relax();
-       /* And now, we can't trust parent->dot, and need to determine our dot from
-        * the ref we obtained. */
-       new_proc->dot = container_of(new_dot_ref, struct chan, ref);
+
+       rcu_read_lock();
+       new_dot = rcu_dereference(parent->dot);
+       kref_get(&new_dot->ref, 1);
+       rcu_read_unlock();
+       new_proc->dot = new_dot;
+
        poperror();
        return 0;
 }
index 2481c7a..7e72095 100644 (file)
@@ -2126,8 +2126,11 @@ static intreg_t sys_chdir(struct proc *p, pid_t pid, const char *path,
                proc_decref(target);
                return -1;
        }
-       /* TODO: 9ns support */
        retval = do_chdir(&target->fs_env, t_path);
+       if (retval < 0) {
+               unset_errno();
+               retval = syschdir(t_path);
+       }
        free_path(p, t_path);
        proc_decref(target);
        return retval;
@@ -2142,10 +2145,10 @@ static intreg_t sys_fchdir(struct proc *p, pid_t pid, int fd)
                return -1;
        file = get_file_from_fd(&p->open_files, fd);
        if (!file) {
-               /* TODO: 9ns */
-               set_errno(EBADF);
+               unset_errno();
+               retval = sysfchdir(fd);
                proc_decref(target);
-               return -1;
+               return retval;
        }
        retval = do_fchdir(&target->fs_env, file);
        kref_put(&file->f_kref);