Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pagemap-cache: handle short reads #2411

Merged
merged 2 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions criu/pagemap-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ static int pmc_fill_cache(pmc_t *pmc, const struct vma_area *vma)

int pmc_fill(pmc_t *pmc, u64 start, u64 end)
{
size_t size_map;
size_t size_map, off;

pmc->start = start;
pmc->end = end;
Expand Down Expand Up @@ -204,10 +204,17 @@ int pmc_fill(pmc_t *pmc, u64 start, u64 end)
pmc->regs_idx = 0;
pmc->end = args.walk_end;
} else {
if (pread(pmc->fd, pmc->map, size_map, PAGEMAP_PFN_OFF(pmc->start)) != size_map) {
pmc_zap(pmc);
pr_perror("Can't read %d's pagemap file", pmc->pid);
return -1;
for (off = 0; off != size_map;) {
ssize_t ret;
char *ptr = (char *)pmc->map;

ret = pread(pmc->fd, ptr + off, size_map - off, PAGEMAP_PFN_OFF(pmc->start) + off);
Fixed Show fixed Hide fixed
if (ret == -1) {
pmc_zap(pmc);
pr_perror("Can't read %d's pagemap file", pmc->pid);
return -1;
}
off += ret;
}
}

Expand Down
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
Loading