Skip to content

Commit

Permalink
util-lib: Add sparc64 support for process creation (#3348)
Browse files Browse the repository at this point in the history
The current raw_clone function takes two arguments, the cloning flags and
a pointer to the stack for the cloned child. The raw cloning without
passing a "thread main" function does not make sense if a new stack is
specified, as it returns in both the parent and the child, which will fail
in the child as the stack is virgin. All uses of raw_clone indeed pass NULL
for the stack pointer which indicates that both processes should share the
stack address (so you better don't pass CLONE_VM).

This commit refactors the code to not require the caller to pass the stack
address, as NULL is the only sensible option. It also adds the magic code
needed to make raw_clone work on sparc64, which does not return 0 in %o0
for the child, but indicates the child process by setting %o1 to non-zero.
This refactoring is not plain aesthetic, because non-NULL stack addresses
need to get mangled before being passed to the clone syscall (you have to
apply STACK_BIAS), whereas NULL must not be mangled. Implementing the
conditional mangling of the stack address would needlessly complicate the
code.

raw_clone is moved to a separete header, because the burden of including
the assert machinery and sched.h shouldn't be applied to every user of
missing_syscalls.h
  • Loading branch information
karcherm authored and keszybz committed May 30, 2016
1 parent 8d76eea commit 8869a0b
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 19 deletions.
1 change: 1 addition & 0 deletions Makefile.am
Expand Up @@ -746,6 +746,7 @@ noinst_LTLIBRARIES += \
libbasic_la_SOURCES = \
src/basic/missing.h \
src/basic/missing_syscall.h \
src/basic/raw-clone.h \
src/basic/capability-util.c \
src/basic/capability-util.h \
src/basic/conf-files.c \
Expand Down
12 changes: 0 additions & 12 deletions src/basic/missing_syscall.h
Expand Up @@ -178,18 +178,6 @@ static inline int setns(int fd, int nstype) {

/* ======================================================================= */

static inline int raw_clone(unsigned long flags, void *child_stack) {
#if defined(__s390__) || defined(__CRIS__)
/* On s390 and cris the order of the first and second arguments
* of the raw clone() system call is reversed. */
return (int) syscall(__NR_clone, child_stack, flags);
#else
return (int) syscall(__NR_clone, flags, child_stack);
#endif
}

/* ======================================================================= */

static inline pid_t raw_getpid(void) {
#if defined(__alpha__)
return (pid_t) syscall(__NR_getxpid);
Expand Down
3 changes: 2 additions & 1 deletion src/basic/process-util.c
Expand Up @@ -48,6 +48,7 @@
#include "macro.h"
#include "missing.h"
#include "process-util.h"
#include "raw-clone.h"
#include "signal-util.h"
#include "stat-util.h"
#include "string-table.h"
Expand Down Expand Up @@ -726,7 +727,7 @@ void valgrind_summary_hack(void) {
#ifdef HAVE_VALGRIND_VALGRIND_H
if (getpid() == 1 && RUNNING_ON_VALGRIND) {
pid_t pid;
pid = raw_clone(SIGCHLD, NULL);
pid = raw_clone(SIGCHLD);
if (pid < 0)
log_emergency_errno(errno, "Failed to fork off valgrind helper: %m");
else if (pid == 0)
Expand Down
81 changes: 81 additions & 0 deletions src/basic/raw-clone.h
@@ -0,0 +1,81 @@
#pragma once

/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
Copyright 2016 Michael Karcher
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/

#include <sched.h>
#include <sys/syscall.h>

#include "log.h"
#include "macro.h"

/**
* raw_clone() - uses clone to create a new process with clone flags
* @flags: Flags to pass to the clone system call
*
* Uses the clone system call to create a new process with the cloning
* flags and termination signal passed in the flags parameter. Opposed
* to glibc's clone funtion, using this function does not set up a
* separate stack for the child, but relies on copy-on-write semantics
* on the one stack at a common virtual address, just as fork does.
*
* To obtain copy-on-write semantics, flags must not contain CLONE_VM,
* and thus CLONE_THREAD and CLONE_SIGHAND (which require CLONE_VM) are
* not usabale.
* Additionally, as this function does not pass the ptid, newtls and ctid
* parameters to the kernel, flags must not contain CLONE_PARENT_SETTID,
* CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID or CLONE_SETTLS.
*
* Returns: 0 in the child process and the child process id in the parent.
*/
static inline int raw_clone(unsigned long flags) {
assert((flags & (CLONE_VM|CLONE_PARENT_SETTID|CLONE_CHILD_SETTID|
CLONE_CHILD_CLEARTID|CLONE_SETTLS)) == 0);
#if defined(__s390__) || defined(__CRIS__)
/* On s390 and cris the order of the first and second arguments
* of the raw clone() system call is reversed. */
return (int) syscall(__NR_clone, NULL, flags);
#elif defined(__sparc__) && defined(__arch64__)
{
/**
* sparc64 always returns the other process id in %o0, and
* a boolean flag whether this is the child or the parent in
* %o1. Inline assembly is needed to get the flag returned
* in %o1.
*/
int in_child;
int child_pid;
asm volatile("mov %2, %%g1\n\t"
"mov %3, %%o0\n\t"
"mov 0 , %%o1\n\t"
"t 0x6d\n\t"
"mov %%o1, %0\n\t"
"mov %%o0, %1" :
"=r"(in_child), "=r"(child_pid) :
"i"(__NR_clone), "r"(flags) :
"%o1", "%o0", "%g1" );
if (in_child)
return 0;
else
return child_pid;
}
#else
return (int) syscall(__NR_clone, flags, NULL);
#endif
}
5 changes: 3 additions & 2 deletions src/core/main.c
Expand Up @@ -70,6 +70,7 @@
#include "parse-util.h"
#include "proc-cmdline.h"
#include "process-util.h"
#include "raw-clone.h"
#include "rlimit-util.h"
#include "selinux-setup.h"
#include "selinux-util.h"
Expand Down Expand Up @@ -162,7 +163,7 @@ noreturn static void crash(int sig) {
/* We want to wait for the core process, hence let's enable SIGCHLD */
(void) sigaction(SIGCHLD, &sa, NULL);

pid = raw_clone(SIGCHLD, NULL);
pid = raw_clone(SIGCHLD);
if (pid < 0)
log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
else if (pid == 0) {
Expand Down Expand Up @@ -221,7 +222,7 @@ noreturn static void crash(int sig) {
log_notice("Executing crash shell in 10s...");
(void) sleep(10);

pid = raw_clone(SIGCHLD, NULL);
pid = raw_clone(SIGCHLD);
if (pid < 0)
log_emergency_errno(errno, "Failed to fork off crash shell: %m");
else if (pid == 0) {
Expand Down
6 changes: 3 additions & 3 deletions src/nspawn/nspawn.c
Expand Up @@ -85,6 +85,7 @@
#include "process-util.h"
#include "ptyfwd.h"
#include "random-util.h"
#include "raw-clone.h"
#include "rm-rf.h"
#include "selinux-util.h"
#include "signal-util.h"
Expand Down Expand Up @@ -2938,8 +2939,7 @@ static int outer_child(
pid = raw_clone(SIGCHLD|CLONE_NEWNS|
(arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS) |
(arg_private_network ? CLONE_NEWNET : 0) |
(arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER : 0),
NULL);
(arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER : 0));
if (pid < 0)
return log_error_errno(errno, "Failed to fork inner child: %m");
if (pid == 0) {
Expand Down Expand Up @@ -3608,7 +3608,7 @@ int main(int argc, char *argv[]) {
goto finish;
}

pid = raw_clone(SIGCHLD|CLONE_NEWNS, NULL);
pid = raw_clone(SIGCHLD|CLONE_NEWNS);
if (pid < 0) {
if (errno == EINVAL)
r = log_error_errno(errno, "clone() failed, do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in): %m");
Expand Down
3 changes: 2 additions & 1 deletion src/test/test-util.c
Expand Up @@ -26,6 +26,7 @@
#include "def.h"
#include "fileio.h"
#include "fs-util.h"
#include "raw-clone.h"
#include "rm-rf.h"
#include "string-util.h"
#include "util.h"
Expand Down Expand Up @@ -244,7 +245,7 @@ static void test_raw_clone(void) {
log_info("before clone: getpid()→"PID_FMT, parent);
assert_se(raw_getpid() == parent);

pid = raw_clone(0, NULL);
pid = raw_clone(0);
assert_se(pid >= 0);

pid2 = raw_getpid();
Expand Down

0 comments on commit 8869a0b

Please sign in to comment.