Re: [PATCH 2/3] plugin/amdgpu: Add topology dump file

Tvrtko Ursulin <[email protected]> Fri, 17 Apr 2026 10:07:41 +0100
Newsgroups dev.linux.lists.criu
Message-ID <[email protected]>
On 16/04/2026 19:26, Francis, David wrote:
>> Ah neat, but I am guessing the data comes from kfd? At some point we
>> will need to bite the bullet and start designing uapi for an amdgpu only
>> world.
> 
> No, the data comes solely from sysfs in this case.

But exported by kfd, no? Ie. /sys/class/kfd/kfd/topology/nodes/. I 
understand the goal is to migrate away from kfd which is why I wondered 
if it makes sense to add an image based of both internal and external 
kfd data.

> No urgency on merging this since it doesn't do much without more patches
> but also unlikely to cause problems on its own - if kfd is present, the plugin
> will continue to make the same dump it always did.
> 
> Review would be appreciated, thanks.

In one aspect it is better than my hack of allow restore from a single 
to a single GPU system, although even there the gpu id is not stable, 
but on the other hand it does add an image format which looks like a 
dead end from a design persective.

Hm, how does this patch handle gpu id changing across reboots?

Regards,

Tvrtko

> ________________________________________
> From: Tvrtko Ursulin <[email protected]>
> Sent: Thursday, April 16, 2026 10:54 AM
> To: Francis, David; [email protected]
> Subject: Re: [PATCH 2/3] plugin/amdgpu: Add topology dump file
> 
> 
> On 10/04/2026 15:45, David Francis wrote:
>> The state of the source topology (the GPUs, CPUs, and links
>> between them) is saved by the plugin as part of kfd dump.
>>
>> If there is no kfd dump, we need to save the topology anyways.
>>
>> Do so in new file amdgpu-topology.img.
> 
> Ah neat, but I am guessing the data comes from kfd? At some point we
> will need to bite the bullet and start designing uapi for an amdgpu only
> world.
> 
> In the meantime, would you like me to review this in detail to perhaps
> have it merged in the interim? Although in that case backward
> compatibility gets more complicated.
> 
> Regards,
> 
> Tvrtko
> 
>>
>> Signed-off-by: David Francis <[email protected]>
>> ---
>>    plugins/amdgpu/amdgpu_plugin.c      | 84 ++++++++++++++++++++++++++---
>>    plugins/amdgpu/amdgpu_plugin_drm.c  | 64 ++++++++++++++++++++--
>>    plugins/amdgpu/amdgpu_plugin_util.h |  9 ++++
>>    plugins/amdgpu/criu-amdgpu.proto    |  5 ++
>>    4 files changed, 151 insertions(+), 11 deletions(-)
>>
>> diff --git a/plugins/amdgpu/amdgpu_plugin.c b/plugins/amdgpu/amdgpu_plugin.c
>> index 89ab10dac..1e9785440 100644
>> --- a/plugins/amdgpu/amdgpu_plugin.c
>> +++ b/plugins/amdgpu/amdgpu_plugin.c
>> @@ -91,6 +91,9 @@ int current_pid;
>>     */
>>    bool parallel_disabled = false;
>>
>> +bool kfd_dump_complete = false;
>> +bool amdgpu_topology_dump_complete = false;
>> +
>>    pthread_t parallel_thread = 0;
>>    int parallel_thread_result = 0;
>>    /**************************************************************************************************/
>> @@ -189,9 +192,14 @@ int topology_to_devinfo(struct tp_system *sys, struct device_maps *maps, KfdDevi
>>                devinfo->node_id = node->id;
>>
>>                if (NODE_IS_GPU(node)) {
>> -                     devinfo->gpu_id = maps_get_dest_gpu(maps, node->gpu_id);
>> -                     if (!devinfo->gpu_id)
>> -                             continue;
>> +                     if (maps) {
>> +                             devinfo->gpu_id = maps_get_dest_gpu(maps, node->gpu_id);
>> +                             if (!devinfo->gpu_id)
>> +                                     continue;
>> +                     } else {
>> +                             devinfo->gpu_id = node->gpu_id;
>> +                     }
>> +
>>
>>                        devinfo->simd_count = node->simd_count;
>>                        devinfo->mem_banks_count = node->mem_banks_count;
>> @@ -238,9 +246,13 @@ int topology_to_devinfo(struct tp_system *sys, struct device_maps *maps, KfdDevi
>>                                if (!iolink->valid)
>>                                        continue;
>>
>> -                             list_for_each_entry(node2, &sys->nodes, listm_system)
>> -                                     if (node2->id == iolink->node_to_id && maps_get_dest_gpu(maps, node2->gpu_id) != 0)
>> -                                             link_to_present_node = true;
>> +                             if (maps) {
>> +                                     list_for_each_entry(node2, &sys->nodes, listm_system)
>> +                                             if (node2->id == iolink->node_to_id && maps_get_dest_gpu(maps, node2->gpu_id) != 0)
>> +                                                     link_to_present_node = true;
>> +                             } else {
>> +                                     link_to_present_node = true;
>> +                             }
>>
>>                                if (!link_to_present_node)
>>                                        continue;
>> @@ -386,6 +398,11 @@ int amdgpu_plugin_init(int stage)
>>        maps_init(&checkpoint_maps);
>>        maps_init(&restore_maps);
>>
>> +     if (stage == CR_PLUGIN_STAGE__DUMP) {
>> +             kfd_dump_complete = false;
>> +             amdgpu_topology_dump_complete = false;
>> +     }
>> +
>>        if (stage == CR_PLUGIN_STAGE__RESTORE) {
>>                if (has_children(root_item)) {
>>                        pr_info("Parallel restore disabled\n");
>> @@ -1552,6 +1569,7 @@ int amdgpu_plugin_dump_file(int fd, int id)
>>        if (ret)
>>                goto exit;
>>
>> +     kfd_dump_complete = true;
>>        if (!plugin_added_to_inventory) {
>>                ret = add_inventory_plugin(CR_PLUGIN_DESC.name);
>>                if (ret) {
>> @@ -1908,6 +1926,60 @@ int amdgpu_plugin_restore_file(int id, bool *retry_needed)
>>
>>                pr_info("render node gpu_id = 0x%04x\n", rd->gpu_id);
>>
>> +             if (list_empty(&restore_maps.cpu_maps) && list_empty(&restore_maps.gpu_maps)) {
>> +                     AmdgpuDevinfo *ad;
>> +
>> +                     pr_info("No restore maps found, making them from topology file\n");
>> +
>> +                     img_fp = open_img_file(IMG_AMDGPU_TOPOLOGY_FILE, false, &img_size, true);
>> +                     if (!img_fp) {
>> +                             pr_err("Failed to find either kfd or amdgpu src topology information\n");
>> +                             ret = -EINVAL;
>> +                             goto exit;
>> +                     }
>> +
>> +                     buf = xmalloc(img_size);
>> +                     if (!buf) {
>> +                             pr_err("Failed to allocate memory\n");
>> +                             return -ENOMEM;
>> +                     }
>> +
>> +                     ret = read_fp(img_fp, buf, img_size);
>> +                     if (ret) {
>> +                             pr_err("Unable to read from %s\n", IMG_AMDGPU_TOPOLOGY_FILE);
>> +                             ret = -EINVAL;
>> +                             goto exit;
>> +                     }
>> +
>> +                     ad = amdgpu_devinfo__unpack(NULL, img_size, buf);
>> +                     if (rd == NULL) {
>> +                             pr_perror("Unable to parse the amdgpu topology message\n");
>> +                             fclose(img_fp);
>> +                             ret = -EINVAL;
>> +                             goto exit;
>> +                     }
>> +                     fclose(img_fp);
>> +
>> +                     ret = devinfo_to_topology(ad->device_entries, ad->num_of_devices, &src_topology);
>> +                     if (ret) {
>> +                             pr_err("Failed to convert amdgpu device information to topology\n");
>> +                             ret = -EINVAL;
>> +                             goto exit;
>> +                     }
>> +
>> +                     ret = topology_parse(&dest_topology, "Local");
>> +                     if (ret) {
>> +                             pr_err("Failed to parse local system topology\n");
>> +                             goto exit;
>> +                     }
>> +
>> +                     ret = set_restore_gpu_maps(&src_topology, &dest_topology, &restore_maps);
>> +                     if (ret) {
>> +                             pr_err("Failed to map GPUs\n");
>> +                             goto exit;
>> +                     }
>> +             }
>> +
>>                target_gpu_id = maps_get_dest_gpu(&restore_maps, rd->gpu_id);
>>                if (!target_gpu_id) {
>>                        fd = -ENODEV;
>> diff --git a/plugins/amdgpu/amdgpu_plugin_drm.c b/plugins/amdgpu/amdgpu_plugin_drm.c
>> index c1dfb2dd4..a4c650753 100644
>> --- a/plugins/amdgpu/amdgpu_plugin_drm.c
>> +++ b/plugins/amdgpu/amdgpu_plugin_drm.c
>> @@ -467,11 +467,65 @@ int amdgpu_plugin_drm_dump_file(int fd, int id, struct stat *drm)
>>                return -ENODEV;
>>        }
>>
>> -     /* Get the GPU_ID of the DRM device */
>> -     rd->gpu_id = maps_get_dest_gpu(&checkpoint_maps, tp_node->gpu_id);
>> -     if (!rd->gpu_id) {
>> -             pr_err("Failed to find valid gpu_id for the device = %d\n", rd->gpu_id);
>> -             return -ENODEV;
>> +     if (kfd_dump_complete) {
>> +             /* Get the GPU_ID of the DRM device */
>> +             rd->gpu_id = maps_get_dest_gpu(&checkpoint_maps, tp_node->gpu_id);
>> +             if (!rd->gpu_id) {
>> +                     pr_err("Failed to find valid gpu_id for the device = %d\n", rd->gpu_id);
>> +                     return -ENODEV;
>> +             }
>> +     } else {
>> +             rd->gpu_id = tp_node->gpu_id;
>> +
>> +             if (!amdgpu_topology_dump_complete) {
>> +                     AmdgpuDevinfo *ad = NULL;
>> +                     unsigned char *buf;
>> +
>> +                     ad = xmalloc(sizeof(*ad));
>> +                     amdgpu_devinfo__init(ad);
>> +
>> +                     ad->num_of_devices = src_topology.num_nodes;
>> +
>> +                     ad->device_entries = xmalloc(sizeof(KfdDeviceEntry *) * ad->num_of_devices);
>> +                     if (!ad->device_entries) {
>> +                             pr_err("Failed to allocate device_entries\n");
>> +                             return -ENOMEM;
>> +                     }
>> +
>> +                     for (int i = 0; i < ad->num_of_devices; i++) {
>> +                             KfdDeviceEntry *entry = xzalloc(sizeof(*entry));
>> +
>> +                             if (!entry) {
>> +                                     pr_err("Failed to allocate entry\n");
>> +                                     return -ENOMEM;
>> +                             }
>> +
>> +                             kfd_device_entry__init(entry);
>> +
>> +                             ad->device_entries[i] = entry;
>> +                             ad->n_device_entries++;
>> +                     }
>> +
>> +                     topology_to_devinfo(&src_topology, NULL, ad->device_entries);
>> +
>> +                     len = amdgpu_devinfo__get_packed_size(ad);
>> +
>> +                     buf = xmalloc(len);
>> +                     if (!buf) {
>> +                             pr_perror("Failed to allocate memory to store protobuf");
>> +                             return -ENOMEM;
>> +                     }
>> +
>> +                     amdgpu_devinfo__pack(ad, buf);
>> +
>> +                     ret = write_img_file(IMG_AMDGPU_TOPOLOGY_FILE, buf, len);
>> +                     if (ret) {
>> +                             pr_err("Failed to write image file %s\n", IMG_AMDGPU_TOPOLOGY_FILE);
>> +                             return -EINVAL;
>> +                     }
>> +
>> +                     amdgpu_topology_dump_complete = true;
>> +             }
>>        }
>>
>>        len = criu_render_node__get_packed_size(rd);
>> diff --git a/plugins/amdgpu/amdgpu_plugin_util.h b/plugins/amdgpu/amdgpu_plugin_util.h
>> index 69b98a31c..ccfe30b49 100644
>> --- a/plugins/amdgpu/amdgpu_plugin_util.h
>> +++ b/plugins/amdgpu/amdgpu_plugin_util.h
>> @@ -2,6 +2,7 @@
>>    #define __AMDGPU_PLUGIN_UTIL_H__
>>
>>    #include <libdrm/amdgpu.h>
>> +#include "criu-amdgpu.pb-c.h"
>>
>>    #ifndef _GNU_SOURCE
>>    #define _GNU_SOURCE 1
>> @@ -59,6 +60,9 @@
>>    /* Name of file having serialized data of DRM device buffer objects (BOs) */
>>    #define IMG_DRM_PAGES_FILE "amdgpu-drm-pages-%d-%d-%04x.img"
>>
>> +/* Name of file containing the source device topology (generated only if IMG_KFD_FILE is not)*/
>> +#define IMG_AMDGPU_TOPOLOGY_FILE "amdgpu-topology.img"
>> +
>>    /* Helper macros to Checkpoint and Restore a ROCm file */
>>    #define HSAKMT_SHM_PATH                     "/dev/shm/hsakmt_shared_mem"
>>    #define HSAKMT_SHM                          "/hsakmt_shared_mem"
>> @@ -115,6 +119,9 @@ extern bool kfd_vram_size_check;
>>    extern bool kfd_numa_check;
>>    extern bool kfd_capability_check;
>>
>> +extern bool kfd_dump_complete;
>> +extern bool amdgpu_topology_dump_complete;
>> +
>>    int read_fp(FILE *fp, void *buf, const size_t buf_len);
>>    int write_fp(FILE *fp, const void *buf, const size_t buf_len);
>>    int read_file(const char *file_path, void *buf, const size_t buf_len);
>> @@ -142,4 +149,6 @@ int sdma_copy_bo(int shared_fd, uint64_t size, FILE *storage_fp,
>>
>>    int serve_out_dmabuf_fd(int handle, int fd);
>>
>> +int topology_to_devinfo(struct tp_system *sys, struct device_maps *maps, KfdDeviceEntry **deviceEntries);
>> +
>>    #endif              /* __AMDGPU_PLUGIN_UTIL_H__ */
>> diff --git a/plugins/amdgpu/criu-amdgpu.proto b/plugins/amdgpu/criu-amdgpu.proto
>> index 7682a8f21..6e44e22aa 100644
>> --- a/plugins/amdgpu/criu-amdgpu.proto
>> +++ b/plugins/amdgpu/criu-amdgpu.proto
>> @@ -93,3 +93,8 @@ message criu_render_node {
>>    message criu_dmabuf_node {
>>        required uint32 gem_handle = 1;
>>    }
>> +
>> +message amdgpu_devinfo {
>> +     required uint32 num_of_devices = 1;
>> +     repeated kfd_device_entry device_entries = 2;
>> +}
>> \ No newline at end of file
>