Skip to content

Commit 72f290f

Browse files
singh264tajilaJasonFengJ9keithc-ca
committed
Address comments
Co-authored-by: Tobi Ajila <[email protected]> Co-authored-by: Jason Feng <[email protected]> Co-authored-by: Keith W. Campbell <[email protected]> Signed-off-by: Amarpreet Singh <[email protected]>
1 parent 5e8cfd9 commit 72f290f

File tree

3 files changed

+354
-314
lines changed

3 files changed

+354
-314
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
/*
2+
* ===========================================================================
3+
* (c) Copyright IBM Corp. 2024, 2024 All Rights Reserved
4+
* ===========================================================================
5+
*/
6+
7+
#include "criuhelpers.h"
8+
9+
#if defined(J9VM_OPT_CRAC_SUPPORT)
10+
/**
11+
* Get the value of a command line option in the array of command line arguments.
12+
* @param[in] optionName The name of the command line option to search for
13+
* @param[in] argc The number of command line arguments
14+
* @param[in] argv The array of command line arguments
15+
* @param[out] error A pointer to an integer for the error code
16+
* @return A pointer to the value of the command line option if found, NULL otherwise
17+
*/
18+
static const char *
19+
getCommandLineOptionValue(const char *optionName, int argc, char **argv, int *error)
20+
{
21+
const char *value = NULL;
22+
int i = 0;
23+
size_t optionNameLength = strlen(optionName);
24+
jboolean optionNameFound = JNI_FALSE;
25+
*error = 0;
26+
for (i = 0; i < argc; i++) {
27+
const char *arg = argv[i];
28+
if (0 == strncmp(arg, optionName, optionNameLength)) {
29+
const char *equals = arg + optionNameLength;
30+
if (('=' == *equals) || ('\0' == *equals)) {
31+
optionNameFound = JNI_TRUE;
32+
value = equals;
33+
if ('=' == *value) {
34+
value += 1;
35+
}
36+
if ('\0' == *value) {
37+
value = NULL;
38+
}
39+
break;
40+
}
41+
}
42+
}
43+
if (!optionNameFound) {
44+
*error = -1;
45+
}
46+
return value;
47+
}
48+
49+
/**
50+
* Get the checkpoint directory from command line options.
51+
* @param[in] argc The number of command line arguments
52+
* @param[in] argv The array of command line arguments
53+
* @param[in/out] error A pointer to an integer for the error code
54+
* @return A pointer to the checkpoint directory if found, NULL otherwise
55+
*/
56+
static const char *
57+
getCheckpointDirectory(int argc, char **argv, int *error)
58+
{
59+
const char *checkpointDirectory = NULL;
60+
const char *checkpointDirectoryPropertyValue = getCommandLineOptionValue("-XX:CRaCRestoreFrom", argc, argv, error);
61+
if (0 == *error) {
62+
if (NULL != checkpointDirectoryPropertyValue) {
63+
checkpointDirectory = checkpointDirectoryPropertyValue;
64+
} else {
65+
JLI_ReportErrorMessage("The value of the command line option -XX:CRaCRestoreFrom was not found.");
66+
*error = -2;
67+
}
68+
}
69+
return checkpointDirectory;
70+
}
71+
72+
/**
73+
* Get the log level specified in the command line arguments.
74+
* @param[in] argc The number of command line arguments
75+
* @param[in] argv The array of command line arguments
76+
* @param[in/out] error A pointer to an integer for the error code
77+
* @return The log level integer if successful, default of 2 otherwise
78+
*/
79+
static int
80+
getLogLevel(int argc, char **argv, int *error)
81+
{
82+
int logLevelValue = 2; /* default */
83+
const char *logLevelPropertyValue = NULL;
84+
logLevelPropertyValue = getCommandLineOptionValue("-Dopenj9.internal.criu.logLevel", argc, argv, error);
85+
if (0 == *error) {
86+
const char *c = logLevelPropertyValue;
87+
if (NULL == c) {
88+
goto done;
89+
}
90+
for (; '\0' != *c; c++) {
91+
if (!isdigit(*c)) {
92+
goto setLogLevelOptionValueNotValidError;
93+
}
94+
}
95+
logLevelValue = atoi(logLevelPropertyValue);
96+
if ((0 <= logLevelValue) && (logLevelValue <= 4)) {
97+
goto done;
98+
} else {
99+
goto setLogLevelOptionValueNotValidError;
100+
}
101+
} else if (-1 == *error) {
102+
goto done;
103+
}
104+
setLogLevelOptionValueNotValidError:
105+
JLI_ReportErrorMessage("The value of the command line option is not valid, option=-Dopenj9.internal.criu.logLevel, value=%s.", logLevelPropertyValue);
106+
*error = -2;
107+
done:
108+
return logLevelValue;
109+
}
110+
111+
/**
112+
* Check if the unprivileged mode is specified in the command line arguments.
113+
* @param[in] argc The number of command line arguments
114+
* @param[in] argv The array of command line arguments
115+
* @param[in/out] error A pointer to an integer for the error code
116+
* @return true if the unprivileged mode option is specified in the command line arguments, false otherwise
117+
*/
118+
static jboolean
119+
isUnprivilegedModeOn(int argc, char **argv, int *error)
120+
{
121+
jboolean isUnprivilegedModeOn = JNI_FALSE;
122+
const char *unprivilegedModePropertyValue = getCommandLineOptionValue("-Dopenj9.internal.criu.unprivilegedMode", argc, argv, error);
123+
if (0 == *error) {
124+
if (NULL == unprivilegedModePropertyValue) {
125+
isUnprivilegedModeOn = JNI_TRUE;
126+
} else {
127+
JLI_ReportErrorMessage("The value of the command line option is not expected, option=-Dopenj9.internal.criu.unprivilegedMode, value=%s.", unprivilegedModePropertyValue);
128+
*error = -2;
129+
}
130+
}
131+
return isUnprivilegedModeOn;
132+
}
133+
134+
/**
135+
* Get the log file specified in the command line arguments.
136+
* @param[in] argc The number of command line arguments
137+
* @param[in] argv The array of command line arguments
138+
* @param[in/out] error A pointer to an integer for the error code
139+
* @return A pointer to the log file string if successful, NULL otherwise
140+
*/
141+
static const char *
142+
getLogFile(int argc, char **argv, int *error)
143+
{
144+
const char *logFile = NULL;
145+
const char *logFilePropertyValue = getCommandLineOptionValue("-Dopenj9.internal.criu.logFile", argc, argv, error);
146+
if (0 == *error) {
147+
if (NULL != logFilePropertyValue) {
148+
logFile = logFilePropertyValue;
149+
} else {
150+
JLI_ReportErrorMessage("The value of the command line option -Dopenj9.internal.criu.logFile was not found.");
151+
*error = -2;
152+
}
153+
}
154+
return logFile;
155+
}
156+
157+
/**
158+
* Restore the system state from a checkpoint using the CRIU tool.
159+
* @param[in] checkpointDirectory The directory containing the checkpoint data
160+
* @param[in] logLevel The log level for CRIU logging
161+
* @param[in] unprivilegedModeOn Indicates whether the unprivileged mode option is on
162+
* @param[in] logFile The log file option for CRIU
163+
* @return 0 if the execution of the 'criu restore' command succeeds, -1 otherwise
164+
*/
165+
static int
166+
restoreFromCheckpoint(const char *checkpointDirectory, int logLevel, jboolean unprivilegedModeOn, const char *logFile)
167+
{
168+
int restoreStatus = 0;
169+
int length = -1;
170+
char *logLevelOption = NULL;
171+
char *logFileOption = NULL;
172+
int argc = 0;
173+
const char *argv[9] = { NULL };
174+
argv[argc++] = "criu";
175+
argv[argc++] = "restore";
176+
argv[argc++] = "-D";
177+
argv[argc++] = checkpointDirectory;
178+
length = snprintf(NULL, 0, "-v%d", logLevel);
179+
if (length < 0) {
180+
char logLevelString[2] = { 0 };
181+
sprintf(logLevelString, "%d", logLevel);
182+
JLI_ReportErrorMessage("Failed to calculate the length of the command option, value=%s, format=%s.", logLevelString, "-v%d");
183+
restoreStatus = -1;
184+
goto done;
185+
}
186+
logLevelOption = (char *)JLI_MemAlloc(length + 1);
187+
if (NULL == logLevelOption) {
188+
char logLevelString[2] = { 0 };
189+
sprintf(logLevelString, "%d", logLevel);
190+
JLI_ReportErrorMessage("Failed to allocate memory for the command option, value=%s, format=%s.", logLevelString, "-v%d");
191+
restoreStatus = -1;
192+
goto done;
193+
}
194+
if (snprintf(logLevelOption, length + 1, "-v%d", logLevel) < 0) {
195+
char logLevelString[2] = { 0 };
196+
sprintf(logLevelString, "%d", logLevel);
197+
JLI_ReportErrorMessage("Failed to allocate memory for the command option, value=%s, format=%s.", logLevelString, "-v%d");
198+
restoreStatus = -1;
199+
goto freeLogLevelOption;
200+
}
201+
argv[argc++] = logLevelOption;
202+
argv[argc++] = "--shell-job";
203+
if (unprivilegedModeOn) {
204+
argv[argc++] = "--unprivileged";
205+
}
206+
if (NULL != logFile) {
207+
length = snprintf(NULL, 0, "--log-file=%s", logFile);
208+
if (length < 0) {
209+
JLI_ReportErrorMessage("Failed to calculate the length of the command option, value=%s, format=%s.", logFile, "--log-file=%s");
210+
restoreStatus = -1;
211+
goto freeLogLevelOption;
212+
}
213+
logFileOption = (char *)JLI_MemAlloc(length + 1);
214+
if (NULL == logFileOption) {
215+
JLI_ReportErrorMessage("Failed to allocate memory for the command option, value=%s, format=%s.", logFile, "--log-file=%s");
216+
restoreStatus = -1;
217+
goto freeLogLevelOption;
218+
}
219+
if (snprintf(logFileOption, length + 1, "--log-file=%s", logFile) < 0) {
220+
JLI_ReportErrorMessage("Failed to allocate memory for the command option, value=%s, format=%s.", logFile, "--log-file=%s");
221+
restoreStatus = -1;
222+
goto freeLogFileOption;
223+
}
224+
argv[argc++] = logFileOption;
225+
}
226+
argv[argc] = NULL;
227+
execvp(argv[0], (char * const *)argv);
228+
/* If execvp returns, there was an error. */
229+
restoreStatus = -1;
230+
freeLogFileOption:
231+
if (logFileOption != NULL) {
232+
JLI_MemFree((void *)logFileOption);
233+
logFileOption = NULL;
234+
}
235+
freeLogLevelOption:
236+
if (logLevelOption != NULL) {
237+
JLI_MemFree((void *)logLevelOption);
238+
logLevelOption = NULL;
239+
}
240+
done:
241+
return restoreStatus;
242+
}
243+
244+
/**
245+
* Handle the restoration of the system state from a checkpoint.
246+
* @param[in] argc The number of command line arguments
247+
* @param[in] argv The array of command line arguments
248+
*/
249+
static void
250+
handleCRaCRestore(int argc, char **argv)
251+
{
252+
const char *checkpointDirectory = NULL;
253+
int error = 0;
254+
int parentProcessExitStatus = EXIT_SUCCESS;
255+
pid_t childProcessPid = 0;
256+
int logLevel = 0;
257+
int childProcessExitStatus = EXIT_SUCCESS;
258+
jboolean unprivilegedModeOn = JNI_FALSE;
259+
const char *logFile = NULL;
260+
int childProcessPidStatus = 0;
261+
int childProcessPidExitStatus = 0;
262+
checkpointDirectory = getCheckpointDirectory(argc, argv, &error);
263+
if (-1 == error) {
264+
return;
265+
}
266+
if (-2 == error) {
267+
JLI_ReportErrorMessage("Failed to get the CRIU checkpoint directory, error=%d.", error);
268+
parentProcessExitStatus = EXIT_FAILURE;
269+
goto doneParentProcess;
270+
}
271+
/*
272+
* The if block will be invoked by the child process,
273+
* and the else block will be invoked by the parent process.
274+
*/
275+
childProcessPid = fork();
276+
if (0 == childProcessPid) {
277+
logLevel = getLogLevel(argc, argv, &error);
278+
if (-2 == error) {
279+
JLI_ReportErrorMessage("Failed to get the CRIU log level, error=%d.", error);
280+
childProcessExitStatus = EXIT_FAILURE;
281+
goto doneChildProcess;
282+
}
283+
unprivilegedModeOn = isUnprivilegedModeOn(argc, argv, &error);
284+
if (-2 == error) {
285+
JLI_ReportErrorMessage("Failed to get the CRIU unprivileged mode, error=%d.", error);
286+
childProcessExitStatus = EXIT_FAILURE;
287+
goto doneChildProcess;
288+
}
289+
logFile = getLogFile(argc, argv, &error);
290+
if (-2 == error) {
291+
JLI_ReportErrorMessage("Failed to get the CRIU log file, error=%d.", error);
292+
childProcessExitStatus = EXIT_FAILURE;
293+
goto doneChildProcess;
294+
}
295+
childProcessExitStatus = restoreFromCheckpoint(checkpointDirectory, logLevel, unprivilegedModeOn, logFile);
296+
doneChildProcess:
297+
exit(childProcessExitStatus);
298+
} else {
299+
waitpid(childProcessPid, &childProcessPidStatus, 0);
300+
if (WIFEXITED(childProcessPidStatus)) {
301+
childProcessPidExitStatus = WEXITSTATUS(childProcessPidStatus);
302+
if (EXIT_SUCCESS == childProcessPidExitStatus) {
303+
JLI_ReportMessage("Completed restore with -XX:CRaCRestoreFrom=PATH.");
304+
} else {
305+
JLI_ReportErrorMessage("Failed to restore from checkpoint, error=%d.", childProcessPidExitStatus);
306+
parentProcessExitStatus = EXIT_FAILURE;
307+
}
308+
} else {
309+
JLI_ReportErrorMessage("The CRIU restore child process failed.");
310+
parentProcessExitStatus = EXIT_FAILURE;
311+
}
312+
}
313+
doneParentProcess:
314+
exit(parentProcessExitStatus);
315+
}
316+
#endif /* defined(J9VM_OPT_CRAC_SUPPORT) */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* ===========================================================================
3+
* (c) Copyright IBM Corp. 2024, 2024 All Rights Reserved
4+
* ===========================================================================
5+
*/
6+
7+
#ifndef CRIUHELPERS_H
8+
#define CRIUHELPERS_H
9+
10+
#include "j9cfg.h"
11+
#if defined(J9VM_OPT_CRAC_SUPPORT)
12+
#include <ctype.h>
13+
#include <sys/wait.h>
14+
15+
static const char *
16+
getCommandLineOptionValue(const char *optionName, int argc, char **argv, int *error);
17+
18+
static const char *
19+
getCheckpointDirectory(int argc, char **argv, int *error);
20+
21+
static int
22+
getLogLevel(int argc, char **argv, int *error);
23+
24+
static jboolean
25+
isUnprivilegedModeOn(int argc, char **argv, int *error);
26+
27+
static const char *
28+
getLogFile(int argc, char **argv, int *error);
29+
30+
static int
31+
restoreFromCheckpoint(const char *checkpointDirectory, int logLevel, jboolean unprivilegedModeOn, const char *logFile);
32+
33+
static void
34+
handleCRaCRestore(int argc, char **argv);
35+
#endif /* defined(J9VM_OPT_CRAC_SUPPORT) */
36+
37+
#endif /* CRIUHELPERS_H */

0 commit comments

Comments
 (0)