Re: [RFC 18/26] plugins/amdgpu: Convert away from libc buffered file IO

"Francis, David" <[email protected]> Tue, 10 Mar 2026 13:11:46 +0000
Newsgroups dev.linux.lists.criu
Message-ID <SA1PR12MB81441007F8ADB0C6D6A7D692EF46A@SA1PR12MB8144.namprd12.prod.outlook.com>
Right, forgot to reply after clarification

This patch and patch 17 are
Reviewed-By: David Francis <[email protected]>

________________________________________
From: Tvrtko Ursulin <[email protected]>
Sent: Monday, March 9, 2026 11:30 AM
To: [email protected]
Cc: Francis, David
Subject: Re: [RFC 18/26] plugins/amdgpu: Convert away from libc buffered file IO


Gentle ping on this one, and patch 17 as well. If those two are reviewed
I can implement the small tweaks as agreed and re-spin the series up to
patch 20. That would be purely cleanup and then I keep churning at the
real stuff.

Tvrtko

On 20/02/2026 12:05, Tvrtko Ursulin wrote:
> 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 <[email protected]>
> ---
>   plugins/amdgpu/amdgpu_plugin.c        | 126 ++++++++++++--------------
>   plugins/amdgpu/amdgpu_plugin_dmabuf.c |  14 ++-
>   plugins/amdgpu/amdgpu_plugin_drm.c    |  32 +++----
>   plugins/amdgpu/amdgpu_plugin_util.c   | 106 ++++++++++++----------
>   plugins/amdgpu/amdgpu_plugin_util.h   |   8 +-
>   5 files changed, 140 insertions(+), 146 deletions(-)
>
> diff --git a/plugins/amdgpu/amdgpu_plugin.c b/plugins/amdgpu/amdgpu_plugin.c
> index a653ba1aa2d9..dc808fe32373 100644
> --- a/plugins/amdgpu/amdgpu_plugin.c
> +++ b/plugins/amdgpu/amdgpu_plugin.c
> @@ -557,7 +557,7 @@ void free_and_unmap(uint64_t size, amdgpu_bo_handle h_bo, amdgpu_va_handle h_va,
>       amdgpu_bo_free(h_bo);
>   }
>
> -int sdma_copy_bo(int shared_fd, uint64_t size, FILE *storage_fp,
> +int sdma_copy_bo(int shared_fd, uint64_t size, int storage_fd,
>                void *buffer, size_t buffer_size, amdgpu_device_handle h_dev,
>                uint64_t max_copy_size, enum sdma_op_type type, bool do_not_free)
>   {
> @@ -689,7 +689,8 @@ int sdma_copy_bo(int shared_fd, uint64_t size, FILE *storage_fp,
>               memset(ib, 0, packets_per_buffer * 28);
>
>               if (type == SDMA_OP_VRAM_WRITE) {
> -                     err = read_fp(storage_fp, buffer, min(bytes_remain, buffer_bo_size));
> +                     err = img_read(storage_fd, buffer,
> +                                    min(bytes_remain, buffer_bo_size));
>                       if (err) {
>                               pr_perror("failed to read from storage");
>                               goto err_bo_list;
> @@ -764,7 +765,8 @@ int sdma_copy_bo(int shared_fd, uint64_t size, FILE *storage_fp,
>               }
>
>               if (type == SDMA_OP_VRAM_READ) {
> -                     err = write_fp(storage_fp, buffer, buffer_bo_size - buffer_space_remain);
> +                     err = img_write(storage_fd, buffer,
> +                                     buffer_bo_size - buffer_space_remain);
>                       if (err) {
>                               pr_perror("failed to write out to storage");
>                               goto err_cs_submit_ib;
> @@ -817,11 +819,11 @@ void *dump_bo_contents(void *_thread_data)
>       struct amdgpu_gpu_info gpu_info = { 0 };
>       amdgpu_device_handle h_dev;
>       size_t max_bo_size = 0, image_size = 0, buffer_size;
> +     int bo_contents_fd = -1;
>       uint64_t max_copy_size;
>       uint32_t major, minor;
>       int num_bos = 0;
>       int i, ret = 0;
> -     FILE *bo_contents_fp = NULL;
>       void *buffer = NULL;
>       char img_path[40];
>
> @@ -862,10 +864,9 @@ void *dump_bo_contents(void *_thread_data)
>       }
>
>       snprintf(img_path, sizeof(img_path), IMG_KFD_PAGES_FILE, thread_data->id, thread_data->gpu_id);
> -     bo_contents_fp = open_img_file(img_path, true, &image_size);
> -     if (!bo_contents_fp) {
> -             pr_perror("Cannot fopen %s", img_path);
> -             ret = -EIO;
> +     bo_contents_fd = open_img_file(img_path, true, &image_size);
> +     if (bo_contents_fd < 0) {
> +             ret = bo_contents_fd;
>               goto exit;
>       }
>
> @@ -879,8 +880,9 @@ void *dump_bo_contents(void *_thread_data)
>               num_bos++;
>
>               /* perform sDMA based vram copy */
> -             ret = sdma_copy_bo(bo_buckets[i].dmabuf_fd, bo_buckets[i].size, bo_contents_fp, buffer, buffer_size, h_dev, max_copy_size,
> -                                SDMA_OP_VRAM_READ, false);
> +             ret = sdma_copy_bo(bo_buckets[i].dmabuf_fd, bo_buckets[i].size,
> +                                bo_contents_fd, buffer, buffer_size, h_dev,
> +                                max_copy_size, SDMA_OP_VRAM_READ, false);
>
>               if (ret) {
>                       pr_err("Failed to drain the BO using sDMA: bo_buckets[%d]\n", i);
> @@ -891,8 +893,8 @@ void *dump_bo_contents(void *_thread_data)
>   exit:
>       pr_info("Thread[0x%x] done num_bos:%d ret:%d\n", thread_data->gpu_id, num_bos, ret);
>
> -     if (bo_contents_fp)
> -             fclose(bo_contents_fp);
> +     if (bo_contents_fd >= 0)
> +             close(bo_contents_fd);
>
>       xfree(buffer);
>
> @@ -909,9 +911,9 @@ void *restore_bo_contents(void *_thread_data)
>       size_t image_size = 0, total_bo_size = 0, max_bo_size = 0, buffer_size;
>       struct amdgpu_gpu_info gpu_info = { 0 };
>       amdgpu_device_handle h_dev;
> +     int bo_contents_fd = -1;
>       uint64_t max_copy_size;
>       uint32_t major, minor;
> -     FILE *bo_contents_fp = NULL;
>       void *buffer = NULL;
>       char img_path[40];
>       int num_bos = 0;
> @@ -936,10 +938,9 @@ void *restore_bo_contents(void *_thread_data)
>                                                                  SDMA_LINEAR_COPY_MAX_SIZE - 1;
>
>       snprintf(img_path, sizeof(img_path), IMG_KFD_PAGES_FILE, thread_data->id, thread_data->gpu_id);
> -     bo_contents_fp = open_img_file(img_path, false, &image_size);
> -     if (!bo_contents_fp) {
> -             pr_perror("Cannot fopen %s", img_path);
> -             ret = -errno;
> +     bo_contents_fd = open_img_file(img_path, false, &image_size);
> +     if (bo_contents_fd < 0) {
> +             ret = bo_contents_fd;
>               goto exit;
>       }
>
> @@ -978,8 +979,9 @@ void *restore_bo_contents(void *_thread_data)
>
>               num_bos++;
>
> -             ret = sdma_copy_bo(bo_buckets[i].dmabuf_fd, bo_buckets[i].size, bo_contents_fp, buffer, buffer_size, h_dev, max_copy_size,
> -                                SDMA_OP_VRAM_WRITE, false);
> +             ret = sdma_copy_bo(bo_buckets[i].dmabuf_fd, bo_buckets[i].size,
> +                                bo_contents_fd, buffer, buffer_size, h_dev,
> +                                max_copy_size, SDMA_OP_VRAM_WRITE, false);
>               if (ret) {
>                       pr_err("Failed to fill the BO using sDMA: bo_buckets[%d]\n", i);
>                       break;
> @@ -991,8 +993,8 @@ void *restore_bo_contents(void *_thread_data)
>   exit:
>       pr_info("Thread[0x%x] done num_bos:%d ret:%d\n", thread_data->gpu_id, num_bos, ret);
>
> -     if (bo_contents_fp)
> -             fclose(bo_contents_fp);
> +     if (bo_contents_fd >= 0)
> +             close(bo_contents_fd);
>
>       xfree(buffer);
>
> @@ -1016,9 +1018,7 @@ int check_hsakmt_shared_mem(uint64_t *shared_mem_size, uint32_t *shared_mem_magi
>
>       /* First 4 bytes of shared file is the magic */
>       ret = read_file(HSAKMT_SHM_PATH, shared_mem_magic, sizeof(*shared_mem_magic));
> -     if (ret)
> -             pr_perror("Failed to read shared mem magic");
> -     else
> +     if (!ret)
>               pr_debug("Shared mem magic:0x%x\n", *shared_mem_magic);
>
>       return 0;
> @@ -1137,15 +1137,12 @@ int amdgpu_id_for_handle(int handle)
>   static int load_img(char *filename, unsigned char **out_buf, size_t *out_len)
>   {
>       unsigned char *buf;
> -     FILE *img_fp;
> +     int fd, ret;
>       size_t len;
> -     int ret;
>
> -     img_fp = open_img_file(filename, false, &len);
> -     if (!img_fp) {
> -             ret = -ENOENT;
> -             goto out;
> -     }
> +     fd = open_img_file(filename, false, &len);
> +     if (fd < 0)
> +             return fd;
>
>       buf = xmalloc(len);
>       if (!buf) {
> @@ -1153,7 +1150,7 @@ static int load_img(char *filename, unsigned char **out_buf, size_t *out_len)
>               goto out_close;
>       }
>
> -     ret = read_fp(img_fp, buf, len);
> +     ret = img_read(fd, buf, len);
>       if (ret) {
>               xfree(buf);
>       } else {
> @@ -1162,11 +1159,7 @@ static int load_img(char *filename, unsigned char **out_buf, size_t *out_len)
>       }
>
>   out_close:
> -     fclose(img_fp);
> -out:
> -     if (ret < 0)
> -             pr_err("Unable to read from %s", filename);
> -
> +     close(fd);
>       return ret;
>   }
>
> @@ -1956,7 +1949,7 @@ int amdgpu_plugin_restore_file(int id, bool *retry_needed)
>       CriuKfd *e = NULL;
>       struct kfd_ioctl_criu_args args = { 0 };
>       size_t img_size;
> -     FILE *img_fp = NULL;
> +     int img_fd;
>
>       *retry_needed = false;
>
> @@ -1967,8 +1960,8 @@ int amdgpu_plugin_restore_file(int id, bool *retry_needed)
>
>       snprintf(img_path, sizeof(img_path), IMG_KFD_FILE, id);
>
> -     img_fp = open_img_file(img_path, false, &img_size);
> -     if (!img_fp)
> +     img_fd = open_img_file(img_path, false, &img_size);
> +     if (img_fd < 0)
>               return amdgpu_plugin_restore_drm_file(id, retry_needed);
>
>       fd = open(AMDGPU_KFD_DEVICE, O_RDWR | O_CLOEXEC);
> @@ -1985,19 +1978,18 @@ int amdgpu_plugin_restore_file(int id, bool *retry_needed)
>       pr_info("KFD Image file size:%ld\n", img_size);
>       buf = xmalloc(img_size);
>       if (!buf) {
> -             fclose(img_fp);
> +             close(img_fd);
>               return -ENOMEM;
>       }
>
> -     ret = read_fp(img_fp, buf, img_size);
> +     ret = img_read(img_fd, buf, img_size);
> +     close(img_fd);
>       if (ret) {
>               pr_perror("Unable to read from %s", img_path);
> -             fclose(img_fp);
>               xfree(buf);
>               return ret;
>       }
>
> -     fclose(img_fp);
>       e = criu_kfd__unpack(NULL, img_size, buf);
>       if (e == NULL) {
>               pr_err("Unable to parse the KFD message %#x\n", id);
> @@ -2254,25 +2246,23 @@ err:
>       return ret;
>   }
>
> -FILE *get_bo_contents_fp(int id, int gpu_id, size_t tot_size)
> +static int get_bo_contents_fd(int id, int gpu_id, size_t tot_size)
>   {
>       char img_path[PATH_MAX];
>       size_t image_size = 0;
> -     FILE *bo_contents_fp = NULL;
> +     int fd;
>
>       snprintf(img_path, sizeof(img_path), IMG_KFD_PAGES_FILE, id, gpu_id);
> -     bo_contents_fp = open_img_file(img_path, false, &image_size);
> -     if (!bo_contents_fp) {
> -             pr_perror("Cannot fopen %s", img_path);
> -             return NULL;
> -     }
> +     fd = open_img_file(img_path, false, &image_size);
> +     if (fd < 0)
> +             return fd;
>
>       if (tot_size != image_size) {
>               pr_err("%s size mismatch (current:%ld:expected:%ld)\n", img_path, image_size, tot_size);
> -             fclose(bo_contents_fp);
> -             return NULL;
> +             close(fd);
> +             return -EINVAL;
>       }
> -     return bo_contents_fp;
> +     return fd;
>   }
>
>   struct parallel_thread_data {
> @@ -2289,7 +2279,7 @@ void *parallel_restore_bo_contents(void *_thread_data)
>       amdgpu_device_handle h_dev;
>       uint64_t max_copy_size;
>       size_t total_bo_size = 0, max_bo_size = 0, buffer_size = 0;
> -     FILE *bo_contents_fp = NULL;
> +     int bo_contents_fd = -1;
>       parallel_restore_entry *entry;
>       parallel_restore_cmd *restore_cmd = thread_data->restore_cmd;
>       int ret = 0;
> @@ -2310,12 +2300,12 @@ void *parallel_restore_bo_contents(void *_thread_data)
>
>       buffer_size = kfd_max_buffer_size > 0 ? min(kfd_max_buffer_size, max_bo_size) : max_bo_size;
>
> -     bo_contents_fp = get_bo_contents_fp(restore_cmd->cmd_head.id, thread_data->gpu_id, total_bo_size);
> -     if (bo_contents_fp == NULL) {
> -             ret = -1;
> +     bo_contents_fd = get_bo_contents_fd(restore_cmd->cmd_head.id, thread_data->gpu_id, total_bo_size);
> +     if (bo_contents_fd < 0) {
> +             ret = bo_contents_fd;
>               goto err_sdma;
>       }
> -     offset = ftell(bo_contents_fp);
> +     offset = lseek(bo_contents_fd, 0, SEEK_CUR);
>       if (offset < 0) {
>               ret = -errno;
>               pr_perror("Failed to alloc aligned memory. Consider setting KFD_MAX_BUFFER_SIZE.");
> @@ -2334,17 +2324,17 @@ void *parallel_restore_bo_contents(void *_thread_data)
>                       continue;
>
>               entry = &restore_cmd->entries[i];
> -             ret = fseeko(bo_contents_fp, entry->read_offset + offset,
> -                          SEEK_SET);
> -             if (ret < 0) {
> +             ret = lseek(bo_contents_fd, entry->read_offset + offset,
> +                         SEEK_SET);
> +             if (ret) {
>                       ret = -errno;
>                       pr_err("Failed to seek for BO using sDMA: bo_buckets[%d]\n", i);
>                       goto err_sdma;
>               }
> -             ret = sdma_copy_bo(restore_cmd->fds_write[entry->write_id], entry->size, bo_contents_fp,
> -                                buffer, buffer_size, h_dev,
> -                                max_copy_size, SDMA_OP_VRAM_WRITE, false);
> -
> +             ret = sdma_copy_bo(restore_cmd->fds_write[entry->write_id],
> +                                entry->size, bo_contents_fd, buffer,
> +                                buffer_size, h_dev, max_copy_size,
> +                                SDMA_OP_VRAM_WRITE, false);
>               if (ret) {
>                       pr_err("Failed to fill the BO using sDMA: bo_buckets[%d]\n", i);
>                       goto err_sdma;
> @@ -2352,8 +2342,8 @@ void *parallel_restore_bo_contents(void *_thread_data)
>       }
>
>   err_sdma:
> -     if (bo_contents_fp)
> -             fclose(bo_contents_fp);
> +     if (bo_contents_fd >= 0)
> +             close(bo_contents_fd);
>       if (buffer)
>               xfree(buffer);
>       amdgpu_device_deinitialize(h_dev);
> diff --git a/plugins/amdgpu/amdgpu_plugin_dmabuf.c b/plugins/amdgpu/amdgpu_plugin_dmabuf.c
> index 859ff42bb76a..fb894de16d75 100644
> --- a/plugins/amdgpu/amdgpu_plugin_dmabuf.c
> +++ b/plugins/amdgpu/amdgpu_plugin_dmabuf.c
> @@ -96,20 +96,19 @@ int __amdgpu_plugin_dmabuf_dump(int dmabuf_fd, int id)
>   int amdgpu_plugin_dmabuf_restore(int id)
>   {
>       char path[PATH_MAX];
> +     int fd_id, img_fd;
>       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);
> -     if (!img_fp) {
> +     img_fd = open_img_file(path, false, &img_size);
> +     if (img_fd < 0) {
>               pr_err("Failed to open dmabuf metadata file: %s\n", path);
> -             return -EINVAL;
> +             return img_fd;
>       }
>
>       pr_debug("dmabuf Image file size:%ld\n", img_size);
> @@ -119,10 +118,9 @@ int amdgpu_plugin_dmabuf_restore(int id)
>               return -ENOMEM;
>       }
>
> -     ret = read_fp(img_fp, buf, img_size);
> -     fclose(img_fp);
> +     ret = img_read(img_fd, buf, img_size);
> +     close(img_fd);
>       if (ret) {
> -             pr_perror("Unable to read from %s", path);
>               xfree(buf);
>               return ret;
>       }
> diff --git a/plugins/amdgpu/amdgpu_plugin_drm.c b/plugins/amdgpu/amdgpu_plugin_drm.c
> index d0f84b46997c..070b5b19ec47 100644
> --- a/plugins/amdgpu/amdgpu_plugin_drm.c
> +++ b/plugins/amdgpu/amdgpu_plugin_drm.c
> @@ -163,8 +163,8 @@ static int restore_bo_contents_drm(int drm_render_minor, CriuRenderNode *rd, int
>       amdgpu_device_handle h_dev;
>       uint64_t max_copy_size;
>       uint32_t major, minor;
> -     FILE *bo_contents_fp = NULL;
>       void *buffer = NULL;
> +     int bo_contents_fd;
>       char img_path[40];
>       int i, ret = 0;
>
> @@ -209,24 +209,23 @@ static int restore_bo_contents_drm(int drm_render_minor, CriuRenderNode *rd, int
>
>               snprintf(img_path, sizeof(img_path), IMG_DRM_PAGES_FILE, rd->id, drm_render_minor, i);
>
> -             bo_contents_fp = open_img_file(img_path, false, &image_size);
> -             if (!bo_contents_fp) {
> -                     ret = -EIO;
> +             bo_contents_fd = open_img_file(img_path, false, &image_size);
> +             if (bo_contents_fd < 0) {
> +                     ret = bo_contents_fd;
>                       pr_err("Failed to open BO image file %s\n", img_path);
>                       break;
>               }
>
> -             ret = sdma_copy_bo(dmabufs[i], rd->bo_entries[i]->size, bo_contents_fp, buffer, buffer_size, h_dev, max_copy_size,
> -                                SDMA_OP_VRAM_WRITE, true);
> +             ret = sdma_copy_bo(dmabufs[i], rd->bo_entries[i]->size,
> +                                bo_contents_fd, buffer, buffer_size, h_dev,
> +                                max_copy_size, SDMA_OP_VRAM_WRITE, true);
> +             close(bo_contents_fd);
>               if (ret) {
>                       pr_err("Failed to fill the BO using sDMA: bo_buckets[%d]\n", i);
>                       break;
>               }
>               pr_debug("** Successfully filled the BO using sDMA: bo_buckets[%d] **\n",
>                        i);
> -
> -             if (bo_contents_fp)
> -                     fclose(bo_contents_fp);
>       }
>
>   exit:
> @@ -307,12 +306,12 @@ int amdgpu_plugin_drm_dump_file(int fd, int id, struct stat *drm)
>               DrmBoEntry *boinfo = rd->bo_entries[i];
>               struct drm_amdgpu_gem_list_handles_entry handle_entry = list_handles_entries[i];
>               union drm_amdgpu_gem_mmap mmap_args = { 0 };
> +             int bo_contents_fd;
>               int dmabuf_fd;
>               uint32_t major, minor;
>               amdgpu_device_handle h_dev;
>               void *buffer = NULL;
>               char img_path[40];
> -             FILE *bo_contents_fp = NULL;
>               int device_fd;
>
>               boinfo->size = handle_entry.size;
> @@ -388,25 +387,24 @@ int amdgpu_plugin_drm_dump_file(int fd, int id, struct stat *drm)
>
>               snprintf(img_path, sizeof(img_path), IMG_DRM_PAGES_FILE, rd->id, rd->drm_render_minor, i);
>               image_size = handle_entry.size;
> -             bo_contents_fp = open_img_file(img_path, true, &image_size);
> -             if (!bo_contents_fp) {
> -                     ret = -EIO;
> +             bo_contents_fd = open_img_file(img_path, true, &image_size);
> +             if (bo_contents_fd < 0) {
> +                     ret = bo_contents_fd;
>                       goto exit;
>               }
>
>               posix_memalign(&buffer, sysconf(_SC_PAGE_SIZE), handle_entry.size);
>
> -             ret = sdma_copy_bo(dmabuf_fd, handle_entry.size, bo_contents_fp, buffer, handle_entry.size, h_dev, 0x1000,
> +             ret = sdma_copy_bo(dmabuf_fd, handle_entry.size, bo_contents_fd,
> +                                buffer, handle_entry.size, h_dev, 0x1000,
>                                  SDMA_OP_VRAM_READ, false);
> +             close(bo_contents_fd);
>               if (ret)
>                       goto exit;
>
>               if (dmabuf_fd != KFD_INVALID_FD)
>                       close(dmabuf_fd);
>
> -             if (bo_contents_fp)
> -                     fclose(bo_contents_fp);
> -
>               ret = amdgpu_device_deinitialize(h_dev);
>               if (ret)
>                       goto exit;
> diff --git a/plugins/amdgpu/amdgpu_plugin_util.c b/plugins/amdgpu/amdgpu_plugin_util.c
> index 5925624740e7..411348b2ce0e 100644
> --- a/plugins/amdgpu/amdgpu_plugin_util.c
> +++ b/plugins/amdgpu/amdgpu_plugin_util.c
> @@ -192,26 +192,38 @@ void clear_dumped_fds()
>       }
>   }
>
> -int read_fp(FILE *fp, void *buf, const size_t buf_len)
> +int img_read(int fd, void *buf, const size_t buf_len)
>   {
> -     size_t len_read;
> +     ssize_t len;
>
> -     len_read = fread(buf, 1, buf_len, fp);
> -     if (len_read != buf_len) {
> -             pr_err("Unable to read file (read:%ld buf_len:%ld)\n", len_read, buf_len);
> -             return -EIO;
> +     len = read(fd, buf, buf_len);
> +     if (len < 0 || len != buf_len) {
> +             int ret;
> +
> +             if (len >= 0)
> +                     errno = EIO;
> +             ret = -errno;
> +             pr_perror("Unable to read file (read:%ld buf_len:%ld)\n",
> +                       len, buf_len);
> +             return ret;
>       }
>       return 0;
>   }
>
> -int write_fp(FILE *fp, const void *buf, const size_t buf_len)
> +int img_write(int fd, const void *buf, const size_t buf_len)
>   {
> -     size_t len_write;
> +     ssize_t len;
>
> -     len_write = fwrite(buf, 1, buf_len, fp);
> -     if (len_write != buf_len) {
> -             pr_err("Unable to write file (wrote:%ld buf_len:%ld)\n", len_write, buf_len);
> -             return -EIO;
> +     len = write(fd, buf, buf_len);
> +     if (len < 0 || len != buf_len) {
> +             int ret;
> +
> +             if (len >= 0)
> +                     errno = EIO;
> +             ret = -errno;
> +             pr_perror("Unable to write file (wrote:%ld buf_len:%ld)\n",
> +                       len, buf_len);
> +             return ret;
>       }
>       return 0;
>   }
> @@ -222,63 +234,60 @@ int write_fp(FILE *fp, const void *buf, const size_t buf_len)
>    * We store the size of the actual contents in the first 8-bytes of
>    * the file. This allows us to determine the file size when using
>    * criu_image_streamer when fseek and fstat are not available. The
> - * FILE * returned is already at the location of the first actual
> + * file descriptor returned is already at the location of the first actual
>    * contents.
>    *
>    * @param path The file path
>    * @param write False for read, true for write
>    * @param size Size of actual contents
> - * @return FILE *if successful, NULL if failed
> + * @return file descriptor if successful, negative integer if failed
>    */
> -FILE *open_img_file(char *path, bool write, size_t *size)
> +int open_img_file(char *path, bool write, size_t *size)
>   {
> -     FILE *fp = NULL;
>       int fd, ret;
>
> -     if (opts.stream)
> +     if (opts.stream) {
>               fd = img_streamer_open(path, write ? O_DUMP : O_RSTR);
> -     else
> -             fd = openat(criu_get_image_dir(), path, write ? (O_WRONLY | O_CREAT) : O_RDONLY, 0600);
> -
> -     if (fd < 0) {
> -             pr_err("%s: Failed to open for %s\n", path, write ? "write" : "read");
> -             return NULL;
> +             if (fd < 0)
> +                     errno = -fd;
> +     } else {
> +             fd = openat(criu_get_image_dir(), path,
> +                         write ? (O_WRONLY | O_CREAT) : O_RDONLY, 0600);
>       }
>
> -     fp = fdopen(fd, write ? "w" : "r");
> -     if (!fp) {
> -             pr_err("%s: Failed get pointer for %s\n", path, write ? "write" : "read");
> -             return NULL;
> +     if (fd < 0) {
> +             pr_perror("%s: Failed to open for %s\n",
> +                       path, write ? "write" : "read");
> +             return fd;
>       }
>
>       if (write)
> -             ret = write_fp(fp, size, sizeof(*size));
> +             ret = img_write(fd, size, sizeof(*size));
>       else
> -             ret = read_fp(fp, size, sizeof(*size));
> -
> +             ret = img_read(fd, size, sizeof(*size));
>       if (ret) {
> -             pr_err("%s:Failed to access file size\n", path);
> -             fclose(fp);
> -             return NULL;
> +             close(fd);
> +             return ret;
>       }
>
>       pr_debug("%s:Opened file for %s with size:%ld\n", path, write ? "write" : "read", *size);
> -     return fp;
> +     return fd;
>   }
>
>   int read_file(const char *file_path, void *buf, const size_t buf_len)
>   {
> -     int ret;
> -     FILE *fp;
> +     int ret, fd;
>
> -     fp = fopen(file_path, "r");
> -     if (!fp) {
> -             pr_err("Cannot fopen %s\n", file_path);
> -             return -errno;
> +     fd = open(file_path, O_RDONLY);
> +     if (fd < 0) {
> +             int ret = errno;
> +
> +             pr_perror("Cannot open %s\n", file_path);
> +             return -ret;
>       }
>
> -     ret = read_fp(fp, buf, buf_len);
> -     fclose(fp); /* this will also close fd */
> +     ret = img_read(fd, buf, buf_len);
> +     close(fd);
>       return ret;
>   }
>
> @@ -296,16 +305,15 @@ int read_file(const char *file_path, void *buf, const size_t buf_len)
>    */
>   int write_img_file(char *path, const void *buf, const size_t buf_len)
>   {
> -     int ret;
> -     FILE *fp;
> +     int ret, fd;
>       size_t len = buf_len;
>
> -     fp = open_img_file(path, true, &len);
> -     if (!fp)
> -             return -errno;
> +     fd = open_img_file(path, true, &len);
> +     if (fd < 0)
> +             return fd;
>
> -     ret = write_fp(fp, buf, buf_len);
> -     fclose(fp); /* this will also close fd */
> +     ret = img_write(fd, buf, buf_len);
> +     close(fd);
>       return ret;
>   }
>
> diff --git a/plugins/amdgpu/amdgpu_plugin_util.h b/plugins/amdgpu/amdgpu_plugin_util.h
> index 014abf35ccb6..eb0c28674d18 100644
> --- a/plugins/amdgpu/amdgpu_plugin_util.h
> +++ b/plugins/amdgpu/amdgpu_plugin_util.h
> @@ -106,11 +106,11 @@ extern bool kfd_vram_size_check;
>   extern bool kfd_numa_check;
>   extern bool kfd_capability_check;
>
> -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 img_read(int fd, void *buf, const size_t buf_len);
> +int img_write(int fd, const void *buf, const size_t buf_len);
>   int read_file(const char *file_path, void *buf, const size_t buf_len);
>   int write_img_file(char *path, const void *buf, const size_t buf_len);
> -FILE *open_img_file(char *path, bool write, size_t *size);
> +int open_img_file(char *path, bool write, size_t *size);
>
>   int record_dumped_fd(int fd, bool is_drm);
>   struct list_head *get_dumped_fds();
> @@ -127,7 +127,7 @@ void clear_restore_state();
>
>   void print_kfd_bo_stat(int bo_cnt, struct kfd_criu_bo_bucket *bo_list);
>
> -int sdma_copy_bo(int shared_fd, uint64_t size, FILE *storage_fp,
> +int sdma_copy_bo(int shared_fd, uint64_t size, int storage_fd,
>                void *buffer, size_t buffer_size, amdgpu_device_handle h_dev,
>                uint64_t max_copy_size, enum sdma_op_type type, bool do_not_free);
>