Allow ktasks to switch_to()
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 7 Dec 2015 21:40:00 +0000 (16:40 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 10 Dec 2015 16:22:24 +0000 (11:22 -0500)
commit66ae3ff7d7039c161aba539ca11a33410a1947ad
tree14d178168044ab61c63c0c4f999ea702999b1f92
parent697248236f83c3e396e70c8640ff859c75136045
Allow ktasks to switch_to()

We had been doing this for a while, but it was buggy.

Ktasks that did a switch_to and then blocked could come back and be in a
different address space, since sem_down()/restart_kthread() didn't know
that suddenly a ktask cared about its address space.  One possibility is
that the kernel would wildly write into the wrong process's address space.

This also may have been a source of bugs where processes wouldn't die
(which is something I found while debugging it).  It sounds familiar; SCPs
not dying under heavy network load to MCPs (IIRC).

Here's the scenario as of a few patches ago:
- A ktask does a switch_to.  old_proc = 0, current = new_proc.  There's no
  refcnting involved.
- The ktask blocks.  Since it was a ktask, in sem_down() kth->proc = 0
- Something else runs, say process 6.  That takes an IRQ that restarts the
  ktask.  That process is still current, and restart_kthread is fine with
that (since ktasks usually ignore whatever process they are in).  Still no
changes to refcnts, and PID 6 is still current.
- The ktask calls switch_back(new_proc, old_proc).  This sets current =
  old_proc, clobbering PID 6's current.  That was a ref counted pointer,
which means we now have an extra ref on PID 6 that will never go away.
That means PID 6 will be stuck DYING forever.

switch_back() had an assumption that new == old, which wasn't playing well
with sem_down's decision to save a ref on current, and restart_kthread's
decision about when to replace current.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/src/process.c