Mark kthreads as ktasks for kernel I/O [2/2]
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 7 Dec 2015 22:23:32 +0000 (17:23 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 10 Dec 2015 16:23:29 +0000 (11:23 -0500)
We had been just doing a switch_to(0).  That's pretty nasty.  Previously,
it'd just blow up if we blocked in KFS (which is how I've been running into
these problems).  That was because we'd switch_to 0, have no current,
block, restart, then not reset current (or decref), as in the switch_to
ktask case.

Now, we aren't using current to tell if we should save the addr space or
not, but we still shouldn't be switch_to(0).

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/kthread.h
kern/src/elf.c
kern/src/kthread.c
kern/src/vfs.c

index f719d93..0776992 100644 (file)
@@ -153,6 +153,9 @@ void __reg_abortable_cv(struct cv_lookup_elm *cle, struct cond_var *cv);
 void dereg_abortable_cv(struct cv_lookup_elm *cle);
 bool should_abort(struct cv_lookup_elm *cle);
 
+uintptr_t switch_to_ktask(void);
+void switch_back_from_ktask(uintptr_t old_ret);
+
 /* qlocks are plan9's binary sempahore, which are wrappers around our sems.
  * Not sure if they'll need irqsave or normal sems. */
 typedef struct semaphore qlock_t;
index 9d1ab58..8a16cbd 100644 (file)
@@ -21,7 +21,7 @@ bool is_valid_elf(struct file *f)
 {
        elf64_t h;
        off64_t o = 0;
-       uintptr_t c = switch_to(0);
+       uintptr_t c = switch_to_ktask();
 
        if (f->f_op->read(f, (char*)&h, sizeof(elf64_t), &o) != sizeof(elf64_t)) {
                goto fail;
@@ -30,10 +30,10 @@ bool is_valid_elf(struct file *f)
                goto fail;
        }
 success:
-       switch_back(0, c);
+       switch_back_from_ktask(c);
        return TRUE;
 fail:
-       switch_back(0, c);
+       switch_back_from_ktask(c);
        return FALSE;
 }
 
@@ -146,9 +146,9 @@ static int load_one_elf(struct proc *p, struct file *f, uintptr_t pg_num,
        void* phdrs = 0;
        int mm_perms, mm_flags = MAP_FIXED;
        
-       /* When reading on behalf of the kernel, we need to make sure no proc is
-        * "current".  This is a bit ghetto (TODO: KFOP) */
-       uintptr_t old_proc = switch_to(0);
+       /* When reading on behalf of the kernel, we need to switch to a ktask so
+        * the VFS (and maybe other places) know. (TODO: KFOP) */
+       uintptr_t old_ret = switch_to_ktask();
 
        /* Read in ELF header. */
        elf64_t elfhdr_storage;
@@ -350,7 +350,7 @@ static int load_one_elf(struct proc *p, struct file *f, uintptr_t pg_num,
 fail:
        if (phdrs)
                kfree(phdrs);
-       switch_back(0, old_proc);
+       switch_back_from_ktask(old_ret);
        return ret;
 }
 
index 9c6c4ed..937fac4 100644 (file)
@@ -886,3 +886,30 @@ bool should_abort(struct cv_lookup_elm *cle)
                return TRUE;
        return FALSE;
 }
+
+/* Sometimes the kernel needs to switch out of process context and into a
+ * 'process-less' kernel thread.  This is basically a ktask.  We use this mostly
+ * when performing file ops as the kernel.  It's nasty, and all uses of this
+ * probably should be removed.  (TODO: KFOP). */
+uintptr_t switch_to_ktask(void)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       struct kthread *kth = pcpui->cur_kthread;
+
+       if (is_ktask(kth))
+               return 0;
+       /* We leave the SAVE_ADDR_SPACE flag on.  Now we're basically a ktask that
+        * cares about its addr space, since we need to return to it (not that we're
+        * leaving). */
+       kth->flags |= KTH_IS_KTASK;
+       return 1;
+}
+
+void switch_back_from_ktask(uintptr_t old_ret)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       struct kthread *kth = pcpui->cur_kthread;
+
+       if (old_ret)
+               kth->flags &= ~KTH_IS_KTASK;
+}
index 875db0c..7ed5651 100644 (file)
@@ -2319,12 +2319,12 @@ void file_release(struct kref *kref)
 
 ssize_t kread_file(struct file *file, void *buf, size_t sz)
 {
-       /* TODO: (KFOP) (VFS kernel read/writes need to have no proc current) */
-       uintptr_t old_proc = switch_to(0);
+       /* TODO: (KFOP) (VFS kernel read/writes need to be from a ktask) */
+       uintptr_t old_ret = switch_to_ktask();
        off64_t dummy = 0;
        ssize_t cpy_amt = file->f_op->read(file, buf, sz, &dummy);
 
-       switch_back(0, old_proc);
+       switch_back_from_ktask(old_ret);
        return cpy_amt;
 }