Re: new execve/kernel_thread design

From: Al Viro
Date: Fri Oct 19 2012 - 11:49:10 EST


On Tue, Oct 16, 2012 at 11:35:08PM +0100, Al Viro wrote:
> 1. Basic rules for process lifetime.
> Except for the initial process (init_task, eventual idle thread on the boot
> CPU) all processes are created by do_fork(). There are three classes of
> those: kernel threads, userland processes and idle threads to be. There are
> few low-level operations involved:
> * a kernel thread can spawn a new kernel thread; the primitive
> doing that is kernel_thread().
> * a userland process can spawn a new userland process; that's
> done by sys_fork()/sys_vfork()/sys_clone()/sys_clone2().
> * a kernel thread can become a userland process. The primitive
> is kernel_execve().
> * a kernel thread can spawn a future idle thread; that's done
> by fork_idle(). Result is *not* scheduled until the secondary CPU gets
> initialized and its state is heavily overwritten in process.

Minor correction: while the first two cases go through do_fork() to
copy_process() to copy_thread(), fork_idle() calls copy_process() directly.

> 4. What is done?
> I've done the conversions for almost all architectures, but quite a few
> are completely untested.
>
> I'm fairly sure about alpha, x86 and um. Tested and I understand the
> architecture well enough. arm, mips and c6x had been tested by architecture
> maintainers. This stuff also works. alpha, arm, x86 and um are fully
> converted in mainline by now.

arm64 fixed and tested by maintainer, put in no-rebase mode.

sparc corrected to avoid branching beyond what ba,pt allows, ACKed by Davem
in that form. In no-rebase mode.

m68k tested and ACKed on coldfire; I think that along with aranym testing
here that is enough. In no-rebase mode.

Surprisingly enough, ia64 one seems to work on actual hardware; I have sent
Tony an incremental patch cleaning copy_thread() up, waiting for results of
testing that on SMP box.

Even more surprisingly, unicore32 variant turned out to contain only one
obvious typo. Fixed and tested by maintainer of unicore32 tree and actually
applied there, I've pulled his branch at that point.

microblaze: some fixes from Michal folded, still breakage with kernel_execve()
side of things.

Since there had been no signs of life from hexagon folks, I'd done (absolutely
blind and untested) tentative patches; see #arch-hexagon. Same situation
as with most of the embedded architectures - i.e. take with a cartload of salt,
that pair of patches is intended to be a possible starting point for producing
something working.

At that point we have the following situation:
alpha done
arm done
arm64 done
avr32 untested
blackfin untested
c6x done
cris untested
frv untested, maintainer going to test
h8300 untested
hexagon untested
ia64 apparently works, needs the final ACK from Tony.
m32r untested
m68k done
microblaze partially tested, maintainer hunting breakage down
mips done
mn10300 untested
openrisc maintainers said to have partially working variant
parisc should work, needs testing and ACK
powerpc should work, needs testing and ACK
s390 should work, needs testing and ACK
score untested
sh untested, maintainers planned reviewing and testing
sparc done
tile maintainers writing that one
um done
unicore32 done
x86 done
xtensa maintainers writing that one

One more thing: AFAICS, just about everything has something along the lines
of
if (!usp)
usp = <current userland sp>
do_fork(flags, usp, ....)
in their sys_clone(). How about taking that into copy_thread()? After
all, the logics there is
copy all the state, including userland stack pointer to child
override userland stack pointer with what the caller passed to
copy_thread()
often enough with "... and if we are about to override it with something
different, do the following extra work". Turning that into
copy all the state, including userland stack pointer to child
if (usp) {
override the userland stack pointer for child and maybe do
some extra work
}
would seem to be a fairly natural thing. Does anybody see problems with
doing that on their architecture? Note that with that fork() becomes
simply
#ifndef CONFIG_MMU
return -EINVAL;
#else
return do_fork(SIGCHLD, 0, current_pt_regs(), 0, NULL, NULL);
#endif
and similar for vfork(). And these can definitely drop the Cthulhu-awful
kludges for obtaining pt_regs (OK, on everything that doesn't do
kernel_thread() via syscall-from-kernel, but by now only xtensa is still
doing that). In some cases we need to do a bit of work before that
(gather callee-saved registers so that the child could get them as on alpha,
mips, m68k, openrisc, parisc, ppc and x86, flush userland register windows
on sparc and get psr/wim values on sparc32), but a lot more architectures
lose the asm wrappers for those and the rest can get rid of assorted
ugliness involved in getting that struct pt_regs *.

BTW, alpha seems to be doing an absolutely pointless work on the way out of
sys_fork() et.al. - saving callee-saved registers is needed, all right,
but why bother restoring all of them on the way out in the parent? All
we need is rp; that's ~0.3Kb of useless reads from memory on each fork()...

The same goes for m68k; there the amount of traffic is less, but still, what
the hell for? Child needs callee-saved registers restored (and usually will
have that done by switch_to()), but the parent needs only to make sure they
are saved and available for copy_thread() to bring them to child (incidentally,
copying registers is needed only when they are not embedded into task_struct.
At least um is doing a memcpy() for no reason whatsoever; fix will be sent
to rw shortly and ISTR seeing something similar on some of the other
architectures).

Another cross-architecture thing: folks, watch out for what's being done with
thread flags; I've just found a lovely bug on alpha where we have prctl(2)
doing non-atomic modifications of those (as in ti->flags = (ti->flags&~x)|y;),
which is obviously broken; TIF_SIGPENDING can be set asynchronously and even
from an interrupt. Fix for this one is going to Linus shortly (adding
a separate field for thread-synchronous flags, taking obviously t-s ones
there, including the UAC_... bunch set by that prctl()), but I don't think
that I can audit that for all architectures efficiently; cursory look has
found a braino on frv (fix being discussed with dhowells), but there may bloody
well be more of that fun.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/