Implement sys_open() with sys_openat() (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 15 Sep 2015 20:00:13 +0000 (16:00 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 28 Sep 2015 19:14:00 +0000 (15:14 -0400)
With namec_from(), we can now build openat() for 9ns.  This commit
builds sys_openat (and the 9ns version), and uses that as a wrapper for
sys_open.  Userspace cannot access this call yet.  Our VFS does not have
support for openat at all.

Also, unlike Linux, we allow an openat from any type of chan, not just a
directory - at least that's the case within the kernel.  What userspace
does (like glibc) is its own thing.

This changes a kernel header, though it shouldn't affect you.

kern/include/ns.h
kern/include/ros/fs.h
kern/src/ns/sysfile.c
kern/src/syscall.c

index b8c4c95..8e7a29e 100644 (file)
@@ -971,7 +971,8 @@ long bindmount(struct chan *c, char *old, int flag, char *spec);
 int sysbind(char *new, char *old, int flags);
 int sysmount(int fd, int afd, char *old, int flags, char *spec);
 int sysunmount(char *old, char *new);
-int sysopen(char *path, int mode);
+int sysopenat(int dirfd, char *path, int vfs_flags);
+int sysopen(char *path, int vfs_flags);
 long unionread(struct chan *c, void *va, long n);
 void read_exactly_n(struct chan *c, void *vp, long n);
 long sysread(int fd, void *va, long n);
index 025c077..4c1fa45 100644 (file)
@@ -64,6 +64,9 @@ struct kstat {
 #define O_CLOEXEC              02000000        /* Set close_on_exec. */
 #define O_REMCLO               04000000        /* Remove on close (unsupported). */
 
+/* Keep this value in sync with glibc (io/fcntl.h) */
+#define AT_FDCWD       -100
+
 #define F_DUPFD                0       /* Duplicate file descriptor */
 #define F_GETFD                1       /* Get file descriptor flags */
 #define F_SETFD                2       /* Set file descriptor flags */
index 8a0d15b..af0224c 100644 (file)
@@ -523,32 +523,40 @@ int sysunmount(char *src_path, char *onto_path)
        return 0;
 }
 
-int sysopen(char *path, int vfs_flags)
+int sysopenat(int fromfd, char *path, int vfs_flags)
 {
-       ERRSTACK(2);
+       ERRSTACK(1);
        int fd;
-       struct chan *c;
+       struct chan *c = 0, *from = 0;
 
        if (waserror()) {
+               cclose(c);
                poperror();
                return -1;
        }
-
        openmode(vfs_flags);    /* error check only */
-       c = namec(path, Aopen, vfs_flags, 0);
-       if (waserror()) {
-               cclose(c);
-               nexterror();
+       if ((path[0] == '/') || (fromfd == AT_FDCWD)) {
+               c = namec(path, Aopen, vfs_flags, 0);
+       } else {
+               /* We don't cclose from.  namec_from will convert it to the new chan
+                * during the walk process (c).  It'll probably close from internally,
+                * and give us something new for c.  On error, namec_from will cclose
+                * from. */
+               from = fdtochan(&current->open_files, fromfd, -1, FALSE, TRUE);
+               c = namec_from(from, path, Aopen, vfs_flags, 0);
        }
        fd = newfd(c, vfs_flags);
        if (fd < 0)
                error(Enofd);
        poperror();
-
-       poperror();
        return fd;
 }
 
+int sysopen(char *path, int vfs_flags)
+{
+       return sysopenat(AT_FDCWD, path, vfs_flags);
+}
+
 long unionread(struct chan *c, void *va, long n)
 {
        ERRSTACK(1);
index c85e0ec..0b75d14 100644 (file)
@@ -1362,15 +1362,15 @@ static intreg_t sys_write(struct proc *p, int fd, const void *buf, int len)
 
 }
 
-/* Checks args/reads in the path, opens the file, and inserts it into the
- * process's open file list. */
-static intreg_t sys_open(struct proc *p, const char *path, size_t path_l,
-                         int oflag, int mode)
+/* Checks args/reads in the path, opens the file (relative to fromfd if the path
+ * is not absolute), and inserts it into the process's open file list. */
+static intreg_t sys_openat(struct proc *p, int fromfd, const char *path,
+                           size_t path_l, int oflag, int mode)
 {
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
        struct systrace_record *t = pcpui->cur_kthread->trace;
        int fd = -1;
-       struct file *file;
+       struct file *file = 0;
        char *t_path;
 
        printd("File %s Open attempt oflag %x mode %x\n", path, oflag, mode);
@@ -1386,19 +1386,25 @@ static intreg_t sys_open(struct proc *p, const char *path, size_t path_l,
                t->datalen = MIN(sizeof(t->data), path_l);
                memmove(t->data, t_path, path_l);
        }
-       sysc_save_str("open %s", t_path);
+       sysc_save_str("open %s at fd %d", t_path, fromfd);
        mode &= ~p->fs_env.umask;
-       file = do_file_open(t_path, oflag, mode);
-       /* VFS */
+       /* Only check the VFS for legacy opens.  It doesn't support openat.  Actual
+        * openats won't check here, and file == 0. */
+       if ((t_path[0] == '/') || (fromfd == AT_FDCWD))
+               file = do_file_open(t_path, oflag, mode);
+       else
+               set_errno(ENOENT);      /* was not in the VFS. */
        if (file) {
+               /* VFS lookup succeeded */
                /* stores the ref to file */
                fd = insert_file(&p->open_files, file, 0, FALSE, oflag & O_CLOEXEC);
                kref_put(&file->f_kref);        /* drop our ref */
                if (fd < 0)
                        warn("File insertion failed");
        } else if (get_errno() == ENOENT) {
+               /* VFS failed due to ENOENT.  Other errors don't fall back to 9ns */
                unset_errno();  /* Go can't handle extra errnos */
-               fd = sysopen(t_path, oflag);
+               fd = sysopenat(fromfd, t_path, oflag);
                /* successful lookup with CREATE and EXCL is an error */
                if (fd != -1) {
                        if ((oflag & O_CREATE) && (oflag & O_EXCL)) {
@@ -1419,6 +1425,12 @@ static intreg_t sys_open(struct proc *p, const char *path, size_t path_l,
        return fd;
 }
 
+static intreg_t sys_open(struct proc *p, const char *path, size_t path_l,
+                         int oflag, int mode)
+{
+       return sys_openat(p, AT_FDCWD, path, path_l, oflag, mode);
+}
+
 static intreg_t sys_close(struct proc *p, int fd)
 {
        struct file *file = get_file_from_fd(&p->open_files, fd);