Skip to content

Commit

Permalink
zdtm: add support for LD_PRELOAD tests
Browse files Browse the repository at this point in the history
This commit adds a `--preload-libfault` option to ZDTM's run command.
This option runs CRIU with LD_PRELOAD to intercept libc functions
such as pread(). This method allows to simulate special cases,
for example, when a successful call to pread() transfers fewer
bytes than requested.

Signed-off-by: Radostin Stoyanov <rstoyanov@fedoraproject.org>
  • Loading branch information
rst0git committed May 28, 2024
1 parent 19461de commit 1e07c20
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 2 deletions.
3 changes: 3 additions & 0 deletions scripts/ci/run-ci-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ make -C test/others/rpc/ run

./test/zdtm.py run -t zdtm/static/env00 --sibling

./test/zdtm.py run -t zdtm/static/maps00 --preload-libfault
./test/zdtm.py run -t zdtm/static/maps02 --preload-libfault

./test/zdtm.py run -t zdtm/transition/maps007 --pre 2 --dedup
./test/zdtm.py run -t zdtm/transition/maps007 --pre 2 --noauto-dedup
./test/zdtm.py run -t zdtm/transition/maps007 --pre 2 --page-server
Expand Down
21 changes: 21 additions & 0 deletions test/libfault/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
CC = gcc
CFLAGS = -c -fPIC -ldl

SRC = libfault.c
OBJ = $(SRC:.c=.o)

LIB = libfault.so

.PHONY: all clean run

all: $(LIB)

$(LIB): $(OBJ)
$(CC) -shared -o $(LIB) $(OBJ)

$(OBJ): $(SRC)
$(CC) $(CFLAGS) $<

clean:
rm -f $(OBJ) $(LIB)

31 changes: 31 additions & 0 deletions test/libfault/libfault.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#define _GNU_SOURCE
#include <unistd.h>
#include <dlfcn.h>
#include <errno.h>

ssize_t (*original_pread)(int fd, void *buf, size_t count, off_t offset) = NULL;

/**
* This function is a wrapper around pread() that is used for testing CRIU's
* handling of cases where pread() returns less data than requested.
*
* pmc_fill() in criu/pagemap.c is a good example of where this can happen.
*/
ssize_t pread64(int fd, void *buf, size_t count, off_t offset)
{
if (!original_pread) {
original_pread = dlsym(RTLD_NEXT, "pread");
if (!original_pread) {
errno = EIO;
return -1;
}
}

/* The following aims to simulate the case when pread() returns less
* data than requested. We need to ensure that CRIU handles such cases. */
if (count > 2048) {
count -= 1024;
}

return original_pread(fd, buf, count, offset);
}
23 changes: 21 additions & 2 deletions test/zdtm.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@
# File to store content of streamed images
STREAMED_IMG_FILE_NAME = "img.criu"

# A library used to preload C functions to simulate
# cases such as partial read with pread().
LIBFAULT_PATH = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"libfault",
"libfault.so"
)

prev_line = None
uuid = uuid.uuid4()

Expand Down Expand Up @@ -628,6 +636,8 @@ def available():
["make", "zdtm_ct"], env=dict(os.environ, MAKEFLAGS=""))
if not os.access("zdtm/lib/libzdtmtst.a", os.F_OK):
subprocess.check_call(["make", "-C", "zdtm/"])
if 'preload_libfault' in opts and opts['preload_libfault']:
subprocess.check_call(["make", "-C", "libfault/"])
if 'rootless' in opts and opts['rootless']:
return
subprocess.check_call(
Expand Down Expand Up @@ -880,6 +890,7 @@ def run(action,
fault=None,
strace=[],
preexec=None,
preload_libfault=False,
nowait=False,
timeout=60):
env = dict(
Expand All @@ -890,6 +901,9 @@ def run(action,
print("Forcing %s fault" % fault)
env['CRIU_FAULT'] = fault

if preload_libfault:
env['LD_PRELOAD'] = LIBFAULT_PATH

cr = subprocess.Popen(strace +
[criu_bin, action, "--no-default-config"] + args,
env=env,
Expand Down Expand Up @@ -980,6 +994,7 @@ def run(action,
fault=None,
strace=[],
preexec=None,
preload_libfault=False,
nowait=False,
timeout=None):
if fault:
Expand Down Expand Up @@ -1065,6 +1080,7 @@ def __init__(self, opts):
self.__criu_bin = opts['criu_bin']
self.__crit_bin = opts['crit_bin']
self.__pre_dump_mode = opts['pre_dump_mode']
self.__preload_libfault = bool(opts['preload_libfault'])
self.__mntns_compat_mode = bool(opts['mntns_compat_mode'])

if opts['rpc']:
Expand Down Expand Up @@ -1192,8 +1208,10 @@ def __criu_act(self, action, opts=[], log=None, nowait=False):
with open("/proc/sys/kernel/ns_last_pid") as ns_last_pid_fd:
ns_last_pid = ns_last_pid_fd.read()

preload_libfault = self.__preload_libfault and action in ['dump', 'pre-dump', 'restore']

ret = self.__criu.run(action, s_args, self.__criu_bin, self.__fault,
strace, preexec, nowait)
strace, preexec, preload_libfault, nowait)

if nowait:
os.close(status_fds[1])
Expand Down Expand Up @@ -2083,7 +2101,7 @@ def run_test(self, name, desc, flavor):
'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup',
'remote_lazy_pages', 'show_stats', 'lazy_migrate', 'stream',
'tls', 'criu_bin', 'crit_bin', 'pre_dump_mode', 'mntns_compat_mode',
'rootless')
'rootless', 'preload_libfault')
arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd}))

if self.__use_log:
Expand Down Expand Up @@ -2788,6 +2806,7 @@ def get_cli_args():
help="Select tests for a shard <index> (0-based)")
rp.add_argument("--test-shard-count", type=int, default=0,
help="Specify how many shards are being run (0=sharding disabled; must be the same for all shards)")
rp.add_argument("--preload-libfault", action="store_true", help="Run criu with library preload to simulate special cases")

lp = sp.add_parser("list", help="List tests")
lp.set_defaults(action=list_tests)
Expand Down
1 change: 1 addition & 0 deletions test/zdtm/criu_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def run(action,
fault=None,
strace=[],
preexec=None,
preload=False,
nowait=False):

config_path = tempfile.mktemp(".conf", "criu-%s-" % action)
Expand Down

0 comments on commit 1e07c20

Please sign in to comment.