Skip to content

Commit

Permalink
Merge pull request #20683 from ymanton/criu-unprivileged
Browse files Browse the repository at this point in the history
Add support for CRIU unprivileged mode
  • Loading branch information
tjwatson authored Apr 9, 2022
2 parents 3b1889b + b3fd8ee commit 4f5ef32
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 8 deletions.
53 changes: 51 additions & 2 deletions dev/com.ibm.ws.kernel.boot.ws-server/publish/bin/server
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@
#TODO need to reflect this to criu checkpoint
# Set to 1-4 with 4 being max verbosity. Two "2" is the default.
#
# CRIU_UNPRIVILEGED - Use criu in unprivileged mode.
# Set to one of true, True, TRUE, 1
# or false, False, FALSE, 0 to continue
# to use criu in privileged mode.
#
# CRIU_EXTRA_ARGS - Pass extra arguments to `criu restore`. Extra arguments are
# appended to the end of the list of arguments and can therefore
# override existing arguments, if desired.
#
# PID_DIR - The directory that should be used for server pid file(s).
# The default value is ${WLP_OUTPUT_DIR}/.pid
#
Expand Down Expand Up @@ -296,6 +305,36 @@ if [ -n "${WLP_SKIP_BOOTSTRAP_AGENT}" ]; then
JAVA_AGENT_QUOTED=
fi

##
## Determine if CRIU supports unprivileged mode.
## Determine which CRIU mode to use, based on current euid, whether or not criu supports unprivileged mode, and the value of the CRIU_UNPRIVILEGED env var.
## Set DO_CRIU_UNPRIVILEGED based on the above.
##
checkCriuUnprivileged()
{
if [ -n "$CRIU_UNPRIVILEGED" ]; then
if [ "${CRIU_UNPRIVILEGED}" = "true" -o "${CRIU_UNPRIVILEGED}" = "1" -o "${CRIU_UNPRIVILEGED}" = "TRUE" -o "${CRIU_UNPRIVILEGED}" = "True" ]; then
# Use unprivileged if explicitly requested; if CRIU doesn't support it we'll hit an error later that will be shown to the user
DO_CRIU_UNPRIVILEGED=true
else
DO_CRIU_UNPRIVILEGED=false
fi
return
fi

# Determine if CRIU supports unprivileged mode
criu --help | grep -q -e '--unprivileged' && CRIU_SUPPORTS_UNPRIVILEGED=true || CRIU_SUPPORTS_UNPRIVILEGED=false

# Determine which CRIU mode to use, based on current euid and value of CRIU_SUPPORTS_UNPRIVILEGED
DO_CRIU_UNPRIVILEGED=false
if [ "$(id -u)" != 0 ]; then
# Not root, unprivileged by default if CRIU supports it
if [ $CRIU_SUPPORTS_UNPRIVILEGED = true ]; then
DO_CRIU_UNPRIVILEGED=true
fi
fi
}

##
## createServer: Function to launch server create
##
Expand Down Expand Up @@ -932,6 +971,11 @@ javaCmd()
fi

JVM_OPTIONS_QUOTED="$JVM_OPTIONS_QUOTED -XX:+EnableCRIUSupport $X_WLP_IMMUTABLE_VARS"

checkCriuUnprivileged
if [ $DO_CRIU_UNPRIVILEGED = true ]; then
JVM_OPTIONS_QUOTED="$JVM_OPTIONS_QUOTED -Dio.openliberty.checkpoint.criu.unprivileged=true"
fi
fi


Expand Down Expand Up @@ -1293,13 +1337,18 @@ criuRestore()
CRIU_LOG_LEVEL=2
fi

checkCriuUnprivileged
if [ $DO_CRIU_UNPRIVILEGED = true ]; then
CRIU_EXTRA_ARGS="--unprivileged $CRIU_EXTRA_ARGS"
fi

if $BACKGROUND_RESTORE
then
mkdirs "${X_PID_DIR}"
rmIfExist "${X_PID_FILE}"
criu restore --cpu-cap=none --file-locks --tcp-established --images-dir=${SERVER_OUTPUT_DIR}/workarea/checkpoint/image \
--shell-job --verbosity=${CRIU_LOG_LEVEL} --log-file ${X_LOG_DIR}/checkpoint/restore.log --pidfile ${X_PID_FILE} \
--restore-detached
--restore-detached ${CRIU_EXTRA_ARGS}
rc=$?
PID=`cat ${X_PID_FILE}`
if [ $rc = 0 ]; then
Expand All @@ -1326,7 +1375,7 @@ criuRestore()
trap "killIfRunning $TAIL_PID" EXIT

criu restore --cpu-cap=none --file-locks --tcp-established --images-dir=${SERVER_OUTPUT_DIR}/workarea/checkpoint/image \
--shell-job --verbosity=${CRIU_LOG_LEVEL} --log-file ${X_LOG_DIR}/checkpoint/restore.log
--shell-job --verbosity=${CRIU_LOG_LEVEL} --log-file ${X_LOG_DIR}/checkpoint/restore.log ${CRIU_EXTRA_ARGS}
rc=$?

kill $TAIL_PID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
public class CheckpointImpl implements RuntimeUpdateListener, ServerReadyStatus {

private static final String CHECKPOINT_STUB_CRIU = "io.openliberty.checkpoint.stub.criu";
private static final String CHECKPOINT_CRIU_UNPRIVILEGED = "io.openliberty.checkpoint.criu.unprivileged";
static final String HOOKS_REF_NAME_SINGLE_THREAD = "hooksSingleThread";
static final String HOOKS_REF_NAME_MULTI_THREAD = "hooksMultiThread";
private static final String DIR_CHECKPOINT = "checkpoint/";
Expand Down Expand Up @@ -110,7 +111,7 @@ public CheckpointImpl(ComponentContext cc, @Reference WsLocationAdmin locAdmin,
*/
this.criu = new ExecuteCRIU() {
@Override
public void dump(Runnable prepare, Runnable restore, File imageDir, String logFileName, File workDir, File envProps) throws CheckpointFailedException {
public void dump(Runnable prepare, Runnable restore, File imageDir, String logFileName, File workDir, File envProps, boolean unprivileged) throws CheckpointFailedException {
prepare.run();
restore.run();
}
Expand Down Expand Up @@ -236,14 +237,16 @@ void checkpoint() throws CheckpointFailedException {
debug(tc, () -> "ExecuteCRIU service does not support checkpoint: " + cpfe.getMessage());
throw cpfe;
}
boolean unprivileged = Boolean.valueOf(cc.getBundleContext().getProperty(CHECKPOINT_CRIU_UNPRIVILEGED));
File imageDir = getImageDir();
debug(tc, () -> "criu attempt dump to '" + imageDir + "' and exit process.");

criu.dump(() -> prepare(singleThreadPrepareHooks),
() -> restore(singleThreadRestoreHooks),
imageDir, CHECKPOINT_LOG_FILE,
getLogsCheckpoint(),
getEnvProperties());
getEnvProperties(),
unprivileged);

debug(tc, () -> "criu dumped to " + imageDir + ", now in recovered process.");
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ public interface ExecuteCRIU {
* @param logFileName
* @param workDir
* @param envProps
* @param unprivileged
* @throws CheckpointFailedException
*/
default void dump(Runnable prepare, Runnable restore, File imageDir, String logFileName, File workDir, File envProps) throws CheckpointFailedException {
default void dump(Runnable prepare, Runnable restore, File imageDir, String logFileName, File workDir, File envProps, boolean unprivileged) throws CheckpointFailedException {
// do nothing
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class ExecuteCRIU_OpenJ9 implements ExecuteCRIU {

@Override
@FFDCIgnore({ JVMCheckpointException.class, SystemCheckpointException.class, RestoreException.class, JVMCRIUException.class, RuntimeException.class })
public void dump(Runnable prepare, Runnable restore, File imageDir, String logFileName, File workDir, File envProps) throws CheckpointFailedException {
public void dump(Runnable prepare, Runnable restore, File imageDir, String logFileName, File workDir, File envProps, boolean unprivileged) throws CheckpointFailedException {
CRIUSupport criuSupport = new CRIUSupport(imageDir.toPath());
criuSupport.registerPreSnapshotHook(prepare);
criuSupport.registerPostRestoreHook(restore);
Expand All @@ -38,6 +38,13 @@ public void dump(Runnable prepare, Runnable restore, File imageDir, String logFi
criuSupport.setWorkDir(workDir.toPath());
criuSupport.setTCPEstablished(true);
criuSupport.registerRestoreEnvFile(envProps.toPath());
if (unprivileged) {
try {
criuSupport.setUnprivileged(true);
} catch (NoSuchMethodError e) {
throw new CheckpointFailedException(Type.UNKNOWN, "JVM does not support CRIU unprivileged mode", e);
}
}
try {
criuSupport.checkpointJVM();
} catch (JVMCheckpointException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private static ExecuteCRIU createCRIUNotSupported(CheckpointFailedException.Type
final CheckpointFailedException criuSupportException = new CheckpointFailedException(type, msg, null);
return new ExecuteCRIU() {
@Override
public void dump(Runnable prepare, Runnable restore, File imageDir, String logFileName, File workDir, File envProps) throws CheckpointFailedException {
public void dump(Runnable prepare, Runnable restore, File imageDir, String logFileName, File workDir, File envProps, boolean unprivileged) throws CheckpointFailedException {
throw criuSupportException;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ public TestCRIU() {
}

@Override
public void dump(Runnable prepare, Runnable restore, File imageDir, String logFileName, File workDir, File envProps) throws CheckpointFailedException {
public void dump(Runnable prepare, Runnable restore, File imageDir, String logFileName, File workDir, File envProps,
boolean unprivileged) throws CheckpointFailedException {
singleThreaded.set(true);
try {
prepare.run();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,18 @@ public CRIUSupport setWorkDir(Path workDir) {
return this;
}

/**
* Controls whether CRIU will be invoked in privileged or unprivileged mode.
* <p>
* Default: false
*
* @param unprivileged
* @return this
*/
public CRIUSupport setUnprivileged(boolean unprivileged) {
return this;
}

/**
* Append new environment variables to the set returned by ProcessEnvironment.getenv(...) upon
* restore. All pre-existing (environment variables from checkpoint run) env
Expand Down

0 comments on commit 4f5ef32

Please sign in to comment.