mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-22 09:58:09 +00:00
Acked-by: Mike Rapoport <rppt@linux.ibm.com> Signed-off-by: Adrian Reber <areber@redhat.com>
261 lines
5.7 KiB
C
261 lines
5.7 KiB
C
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <limits.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/fiemap.h>
|
|
#include "zdtmtst.h"
|
|
|
|
#define FSIZE 0x3B600000ULL
|
|
#define NFILES 10
|
|
#define BUFSIZE (1 << 20)
|
|
|
|
const char *test_doc = "C/R of ten big (951MiB) unlinked files in root dir";
|
|
const char *test_author = "Vitaly Ostrosablin <vostrosablin@virtuozzo.com>";
|
|
|
|
void create_check_pattern(char *buf, size_t count, unsigned char seed)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
buf[i] = seed++;
|
|
}
|
|
|
|
struct fiemap *read_fiemap(int fd)
|
|
{
|
|
struct fiemap *fiemap, *tmp;
|
|
int extents_size;
|
|
|
|
test_msg("Obtaining fiemap for fd %d\n", fd);
|
|
|
|
fiemap = malloc(sizeof(struct fiemap));
|
|
if (fiemap == NULL) {
|
|
pr_perror("Cannot allocate fiemap");
|
|
return NULL;
|
|
}
|
|
memset(fiemap, 0, sizeof(struct fiemap));
|
|
|
|
fiemap->fm_length = FIEMAP_MAX_OFFSET;
|
|
fiemap->fm_start = 0;
|
|
fiemap->fm_flags = 0;
|
|
fiemap->fm_extent_count = 0;
|
|
|
|
if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) {
|
|
pr_perror("FIEMAP ioctl failed");
|
|
free(fiemap);
|
|
return NULL;
|
|
}
|
|
|
|
extents_size = sizeof(struct fiemap_extent) * fiemap->fm_mapped_extents;
|
|
|
|
tmp = realloc(fiemap, sizeof(struct fiemap) + extents_size);
|
|
if (tmp == NULL) {
|
|
free(fiemap);
|
|
pr_perror("Cannot resize fiemap");
|
|
return NULL;
|
|
}
|
|
fiemap = tmp;
|
|
memset(fiemap->fm_extents, 0, extents_size);
|
|
|
|
fiemap->fm_extent_count = fiemap->fm_mapped_extents;
|
|
fiemap->fm_mapped_extents = 0;
|
|
|
|
if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) {
|
|
pr_perror("fiemap ioctl() failed");
|
|
free(fiemap);
|
|
return NULL;
|
|
}
|
|
test_msg("Debugkillme: %x\n", fiemap->fm_mapped_extents);
|
|
|
|
return fiemap;
|
|
}
|
|
|
|
void check_extent_map(struct fiemap *map)
|
|
{
|
|
int i;
|
|
unsigned long long datasize = 0;
|
|
unsigned long long holesize = 0;
|
|
|
|
test_msg("Verifying extent map...\n");
|
|
|
|
for (i = 0; i < map->fm_mapped_extents; i++) {
|
|
test_msg("Extent %d, start %llx, length %llx\n", i, (long long)map->fm_extents[i].fe_logical,
|
|
(long long)map->fm_extents[i].fe_length);
|
|
|
|
if (i == 0)
|
|
holesize = map->fm_extents[i].fe_logical;
|
|
datasize += map->fm_extents[i].fe_length;
|
|
}
|
|
if (holesize != FSIZE) {
|
|
pr_err("Unexpected hole size %llx != %llx\n", (long long)holesize, (unsigned long long)FSIZE);
|
|
exit(1);
|
|
}
|
|
if (datasize != BUFSIZE) {
|
|
pr_err("Unexpected data size %llx != %llx\n", (long long)datasize, (unsigned long long)BUFSIZE);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void compare_file_content(int fildes, int seed)
|
|
{
|
|
char ebuf[BUFSIZE];
|
|
char rbuf[BUFSIZE];
|
|
char linkpath[PATH_MAX];
|
|
int fd;
|
|
struct fiemap *fiemap;
|
|
|
|
ssprintf(linkpath, "/proc/self/fd/%d", fildes);
|
|
|
|
fd = open(linkpath, O_RDONLY | O_LARGEFILE);
|
|
if (fd < 0) {
|
|
pr_perror("Cannot open unlinked file %s", linkpath);
|
|
exit(1);
|
|
}
|
|
|
|
memset(ebuf, 0, BUFSIZE);
|
|
|
|
fiemap = read_fiemap(fd);
|
|
check_extent_map(fiemap);
|
|
free(fiemap);
|
|
|
|
lseek64(fd, FSIZE, SEEK_SET);
|
|
|
|
create_check_pattern(ebuf, BUFSIZE, seed);
|
|
|
|
if (read(fd, rbuf, BUFSIZE) != BUFSIZE) {
|
|
pr_perror("Cannot read %i bytes from file", BUFSIZE);
|
|
goto failed;
|
|
}
|
|
|
|
if (memcmp(&ebuf, &rbuf, BUFSIZE)) {
|
|
pr_err("Control Block: Data mismatch detected\n");
|
|
goto failed;
|
|
}
|
|
|
|
close(fd);
|
|
return;
|
|
failed:
|
|
close(fd);
|
|
exit(1);
|
|
}
|
|
|
|
void read_proc_fd_link(int fd, char *buf)
|
|
{
|
|
ssize_t res;
|
|
char linkpath[PATH_MAX];
|
|
|
|
ssprintf(linkpath, "/proc/%d/fd/%d", getpid(), fd);
|
|
|
|
res = readlink(linkpath, buf, PATH_MAX - 1);
|
|
buf[res] = 0;
|
|
if (res < 0) {
|
|
pr_perror("Cannot read fd symlink %s", linkpath);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
int create_unlinked_file(int fileno)
|
|
{
|
|
int fd;
|
|
char buf[BUFSIZE];
|
|
char fnm[PATH_MAX];
|
|
|
|
ssprintf(fnm, "/unlinked%d", fileno);
|
|
fd = open(fnm, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
|
|
if (fd < 0) {
|
|
pr_perror("Cannot create file %s", fnm);
|
|
exit(1);
|
|
}
|
|
test_msg("Created file: %s, fd %d\n", fnm, fd);
|
|
|
|
if (lseek64(fd, FSIZE, SEEK_SET) < 0) {
|
|
pr_perror("Cannot seek to offset %llx", FSIZE);
|
|
goto failed;
|
|
}
|
|
test_msg("File positioning done, offset=%llx\n", FSIZE);
|
|
|
|
create_check_pattern(&buf[0], BUFSIZE, fileno);
|
|
if (write(fd, buf, BUFSIZE) != BUFSIZE) {
|
|
pr_perror("Cannot write %i bytes to file", BUFSIZE);
|
|
goto failed;
|
|
}
|
|
test_msg("%i bytes written to file\n", BUFSIZE);
|
|
|
|
if (unlink(fnm) < 0) {
|
|
pr_perror("Cannot unlink file %s", fnm);
|
|
goto failed;
|
|
}
|
|
test_msg("File %s is unlinked\n", fnm);
|
|
|
|
return fd;
|
|
failed:
|
|
unlink(fnm);
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int fd[NFILES] = { 0 };
|
|
char links[NFILES][PATH_MAX];
|
|
char link[PATH_MAX];
|
|
int count = 0;
|
|
int tempfd;
|
|
|
|
test_init(argc, argv);
|
|
|
|
/* We need to create 10 unlinked files, each is around 1GB in size */
|
|
for (count = 0; count < NFILES; count++) {
|
|
test_msg("Creating unlinked file %d/%d\n", count + 1, NFILES);
|
|
tempfd = create_unlinked_file(count);
|
|
|
|
if (tempfd < 0) {
|
|
pr_err("Cannot create unlinked file %d/%d\n", count + 1, NFILES);
|
|
return 1;
|
|
}
|
|
|
|
memset(&links[count][0], 0, PATH_MAX);
|
|
read_proc_fd_link(tempfd, &links[count][0]);
|
|
|
|
fd[count] = tempfd;
|
|
}
|
|
test_msg("Created %d unlinked files\n", NFILES);
|
|
|
|
test_daemon();
|
|
test_msg("Test daemonized, PID %d\n", getpid());
|
|
test_waitsig();
|
|
|
|
test_msg("PID %d resumed, doing final checks...\n", getpid());
|
|
|
|
for (count = 0; count < NFILES; count++) {
|
|
test_msg("Processing fd #%d (%d)\n", count, fd[count]);
|
|
|
|
test_msg("Checking symlink consistency...\n");
|
|
memset(&link[0], 0, PATH_MAX);
|
|
read_proc_fd_link(fd[count], &link[0]);
|
|
|
|
if (strcmp(&links[count][0], &link[0])) {
|
|
pr_err("Symlink target %s has changed to %s\n", links[count], link);
|
|
return 1;
|
|
}
|
|
|
|
test_msg("Checking file contents...\n");
|
|
compare_file_content(fd[count], count);
|
|
|
|
test_msg("Closing file descriptor...\n");
|
|
if (close(fd[count]) == -1) {
|
|
pr_perror("Close failed");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
pass();
|
|
return 0;
|
|
}
|