criu/plugins/amdgpu/amdgpu_plugin_dmabuf.c
Tvrtko Ursulin 65f7baaf04 plugins/amdgpu: Move drm file dump and restore into helpers
Given that dump and restore of KFD vs DRM forks into completely parallel
flows inside the respective plugin callbacks, lets split it out by
extracting into helpers. This de-clutters the code flow and makes it
obvious which part is done where.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Reviewed-By: David Francis <David.Francis@amd.com>
2026-04-20 11:03:04 -07:00

205 lines
4.3 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];
size_t img_size;
FILE *img_fp = NULL;
int ret = 0;
CriuDmabufNode *rd = NULL;
unsigned char *buf = NULL;
int fd_id;
snprintf(path, sizeof(path), IMG_DMABUF_FILE, id);
/* Read serialized metadata */
img_fp = open_img_file(path, false, &img_size, true);
if (!img_fp) {
pr_err("Failed to open dmabuf metadata file: %s\n", path);
return -EINVAL;
}
pr_debug("dmabuf Image file size:%ld\n", img_size);
buf = xmalloc(img_size);
if (!buf) {
pr_perror("Failed to allocate memory");
fclose(img_fp);
return -ENOMEM;
}
ret = read_fp(img_fp, buf, img_size);
fclose(img_fp);
if (ret) {
pr_perror("Unable to read from %s", path);
fclose(img_fp);
xfree(buf);
return ret;
}
fclose(img_fp);
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;
}