mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-17 16:47:50 +00:00
Currently the code contains multiple places where callers expect the errno to be valid (implied by calling pr_perror to log file IO errors) after calling open_img_file(), read_fp() and write_fp() helpers. Problem there is that those helpers can destroy the errno courtesy of themselves emitting log messages via fprintf. Furthermore, the callers then sometimes invent the errors to return back to the caller, or even outside of the plugin. On top of that there is no benefit to buffered file IO given the plugin reads and writes in buffer object size chunks, so it it preferrable to just go direct and avoid any possibility of extra copying to and from libc temporary buffers. So lets just convert it all in one swoop to POSIX IO and make sure correct errnos are always propagated to the caller (including to CRIU core). Hopefully this removes all instances of incorrect pr_perror log messages. Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com> Reviewed-By: David Francis <David.Francis@amd.com> # v1 --- v2: * Handle short reads and writes. * Add O_TRUNC. v3: * Handle EINTR and EAGAIN. * Set errno on len == 0. * Use %zu for size_t printing. v4: * Drop shadowed ret. * Drop needless casts.
200 lines
4.2 KiB
C
200 lines
4.2 KiB
C
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <linux/limits.h>
|
|
|
|
#include "common/list.h"
|
|
#include "criu-amdgpu.pb-c.h"
|
|
|
|
#include "xmalloc.h"
|
|
#include "criu-log.h"
|
|
#include "amdgpu_plugin_drm.h"
|
|
#include "amdgpu_plugin_util.h"
|
|
#include "amdgpu_plugin_dmabuf.h"
|
|
#include "fdstore.h"
|
|
|
|
#include "util.h"
|
|
#include "common/scm.h"
|
|
|
|
struct dmabuf {
|
|
int id;
|
|
int dmabuf_fd;
|
|
struct list_head node;
|
|
};
|
|
|
|
static LIST_HEAD(dmabuf_list);
|
|
|
|
/* Return < 0 for error, > 0 for "not a dmabuf" and 0 "is a dmabuf" */
|
|
int get_dmabuf_info(int fd, struct stat *st)
|
|
{
|
|
char path[PATH_MAX];
|
|
|
|
if (read_fd_link(fd, path, sizeof(path)) < 0)
|
|
return -1;
|
|
|
|
if (strncmp(path, DMABUF_LINK, strlen(DMABUF_LINK)) != 0)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int __amdgpu_plugin_dmabuf_dump(int dmabuf_fd, int id)
|
|
{
|
|
int ret = 0;
|
|
char path[PATH_MAX];
|
|
size_t len = 0;
|
|
unsigned char *buf = NULL;
|
|
int gem_handle;
|
|
|
|
gem_handle = handle_for_shared_bo_fd(dmabuf_fd);
|
|
if (gem_handle < 0) {
|
|
pr_err("Failed to get handle for dmabuf_fd = %d\n", dmabuf_fd);
|
|
return -EAGAIN; /* Retry needed */
|
|
}
|
|
|
|
CriuDmabufNode *node = xmalloc(sizeof(*node));
|
|
if (!node) {
|
|
pr_err("Failed to allocate memory for dmabuf node\n");
|
|
return -ENOMEM;
|
|
}
|
|
criu_dmabuf_node__init(node);
|
|
|
|
node->gem_handle = gem_handle;
|
|
|
|
if (node->gem_handle < 0) {
|
|
pr_err("Failed to get handle for dmabuf_fd\n");
|
|
xfree(node);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Serialize metadata to a file */
|
|
snprintf(path, sizeof(path), IMG_DMABUF_FILE, id);
|
|
len = criu_dmabuf_node__get_packed_size(node);
|
|
buf = xmalloc(len);
|
|
if (!buf) {
|
|
pr_err("Failed to allocate buffer for dmabuf metadata\n");
|
|
xfree(node);
|
|
return -ENOMEM;
|
|
}
|
|
criu_dmabuf_node__pack(node, buf);
|
|
ret = write_img_file(path, buf, len);
|
|
|
|
xfree(buf);
|
|
xfree(node);
|
|
return ret;
|
|
}
|
|
|
|
int amdgpu_plugin_dmabuf_restore(int id)
|
|
{
|
|
char path[PATH_MAX];
|
|
int fd_id, img_fd;
|
|
size_t img_size;
|
|
int ret = 0;
|
|
CriuDmabufNode *rd = NULL;
|
|
unsigned char *buf = NULL;
|
|
|
|
snprintf(path, sizeof(path), IMG_DMABUF_FILE, id);
|
|
|
|
/* Read serialized metadata */
|
|
img_fd = open_img_file(path, false, &img_size, true);
|
|
if (img_fd < 0) {
|
|
pr_err("Failed to open dmabuf metadata file: %s\n", path);
|
|
return img_fd;
|
|
}
|
|
|
|
pr_debug("dmabuf Image file size:%ld\n", img_size);
|
|
buf = xmalloc(img_size);
|
|
if (!buf) {
|
|
pr_perror("Failed to allocate memory");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ret = img_read(img_fd, buf, img_size);
|
|
close(img_fd);
|
|
if (ret) {
|
|
xfree(buf);
|
|
return ret;
|
|
}
|
|
|
|
rd = criu_dmabuf_node__unpack(NULL, img_size, buf);
|
|
if (rd == NULL) {
|
|
pr_perror("Unable to parse the dmabuf message %d", id);
|
|
xfree(buf);
|
|
return -1;
|
|
}
|
|
|
|
/* Match GEM handle with shared_dmabuf list */
|
|
fd_id = amdgpu_id_for_handle(rd->gem_handle);
|
|
if (fd_id == -1) {
|
|
pr_err("Failed to find dmabuf_fd for GEM handle = %d\n", rd->gem_handle);
|
|
criu_dmabuf_node__free_unpacked(rd, NULL);
|
|
xfree(buf);
|
|
return 1;
|
|
}
|
|
|
|
int dmabuf_fd = fdstore_get(fd_id);
|
|
if (dmabuf_fd == -1) {
|
|
pr_err("Failed to find dmabuf_fd for GEM handle = %d\n", rd->gem_handle);
|
|
criu_dmabuf_node__free_unpacked(rd, NULL);
|
|
xfree(buf);
|
|
return 1; /* Retry needed */
|
|
}
|
|
|
|
pr_info("Restored dmabuf_fd = %d for GEM handle = %d\n", dmabuf_fd, rd->gem_handle);
|
|
ret = dmabuf_fd;
|
|
|
|
pr_info("Successfully restored dmabuf_fd %d\n", dmabuf_fd);
|
|
criu_dmabuf_node__free_unpacked(rd, NULL);
|
|
xfree(buf);
|
|
return ret;
|
|
}
|
|
|
|
int amdgpu_plugin_dmabuf_dump(int dmabuf_fd, int id)
|
|
{
|
|
int ret;
|
|
|
|
pr_info("Dumping dmabuf fd %d\n", dmabuf_fd);
|
|
|
|
ret = __amdgpu_plugin_dmabuf_dump(dmabuf_fd, id);
|
|
if (ret == -EAGAIN) {
|
|
struct dmabuf *b = xmalloc(sizeof(*b));
|
|
b->id = id;
|
|
b->dmabuf_fd = dmabuf_fd;
|
|
list_add(&b->node, &dmabuf_list);
|
|
return 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int try_dump_dmabuf_list()
|
|
{
|
|
struct dmabuf *b, *t;
|
|
list_for_each_entry_safe(b, t, &dmabuf_list, node) {
|
|
int ret = __amdgpu_plugin_dmabuf_dump(b->dmabuf_fd, b->id);
|
|
if (ret == -EAGAIN)
|
|
continue;
|
|
if (ret)
|
|
return ret;
|
|
list_del(&b->node);
|
|
xfree(b);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int post_dump_dmabuf_check()
|
|
{
|
|
if (!list_empty(&dmabuf_list)) {
|
|
pr_err("Not all dma buffers have been dumped\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|