You haven't implemented objects_index_start yet. I think this is only important later on for dumping BOs with dmabuf handles to avoid exhausting the file-descriptor limit. For now, there should at least be a check for objects_index_start == 0. We can fail if it's not 0 and implement that support later. But allowing non-0 values now without implementing them could lead to ABI breakages later on. Regards, Felix Am 2021-08-19 um 9:37 a.m. schrieb David Yat Sin: > From: Rajneesh Bhardwaj <rajneesh.bhardwaj@xxxxxxx> > > This adds support to discover the buffer objects that belong to a > process being checkpointed. The data corresponding to these buffer > objects is returned to user space plugin running under criu master > context which then stores this info to recreate these buffer objects > during a restore operation. > > Signed-off-by: David Yat Sin <david.yatsin@xxxxxxx> > Signed-off-by: Rajneesh Bhardwaj <rajneesh.bhardwaj@xxxxxxx> > (cherry picked from commit 1f114a541bd21873de905db64bb9efa673274d4b) > (cherry picked from commit 20c435fad57d3201e5402e38ae778f1f0f84a09d) > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 20 +++ > drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 2 + > drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 182 ++++++++++++++++++++++- > drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 3 +- > 4 files changed, 204 insertions(+), 3 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c > index 7e7d8330d64b..99ea29fd12bd 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c > @@ -1181,6 +1181,26 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_device *bdev, > return ttm_pool_free(&adev->mman.bdev.pool, ttm); > } > > +/** > + * amdgpu_ttm_tt_get_userptr - Return the userptr GTT ttm_tt for the current > + * task > + * > + * @tbo: The ttm_buffer_object that contains the userptr > + * @user_addr: The returned value > + */ > +int amdgpu_ttm_tt_get_userptr(const struct ttm_buffer_object *tbo, > + uint64_t *user_addr) > +{ > + struct amdgpu_ttm_tt *gtt; > + > + if (!tbo->ttm) > + return -EINVAL; > + > + gtt = (void *)tbo->ttm; > + *user_addr = gtt->userptr; > + return 0; > +} > + > /** > * amdgpu_ttm_tt_set_userptr - Initialize userptr GTT ttm_tt for the current > * task > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h > index 9e38475e0f8d..dddd76f7a92e 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h > @@ -168,6 +168,8 @@ static inline bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm) > #endif > > void amdgpu_ttm_tt_set_user_pages(struct ttm_tt *ttm, struct page **pages); > +int amdgpu_ttm_tt_get_userptr(const struct ttm_buffer_object *tbo, > + uint64_t *user_addr); > int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo, > uint64_t addr, uint32_t flags); > bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm); > diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c > index 09e2d30515e2..d548e6691d69 100644 > --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c > +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c > @@ -42,6 +42,7 @@ > #include "kfd_svm.h" > #include "amdgpu_amdkfd.h" > #include "kfd_smi_events.h" > +#include "amdgpu_object.h" > > static long kfd_ioctl(struct file *, unsigned int, unsigned long); > static int kfd_open(struct inode *, struct file *); > @@ -1804,6 +1805,44 @@ static int kfd_ioctl_svm(struct file *filep, struct kfd_process *p, void *data) > } > #endif > > +static int criu_dump_process(struct kfd_process *p, struct kfd_ioctl_criu_dumper_args *args) > +{ > + int ret; > + struct kfd_criu_process_bucket *process_bucket; > + struct kfd_criu_process_priv_data *process_priv; > + > + if (args->num_objects != 1) { > + pr_err("Only 1 process supported\n"); > + return -EINVAL; > + } > + > + if (args->objects_size != sizeof(*process_bucket) + sizeof(*process_priv)) { > + pr_err("Invalid objects size for process\n"); > + return -EINVAL; > + } > + > + process_bucket = kzalloc(args->objects_size, GFP_KERNEL); > + if (!process_bucket) > + return -ENOMEM; > + > + /* Private data starts after process bucket */ > + process_priv = (void *)(process_bucket + 1); > + > + process_priv->version = KFD_CRIU_PRIV_VERSION; > + > + process_bucket->priv_data_offset = 0; > + process_bucket->priv_data_size = sizeof(*process_priv); > + > + ret = copy_to_user((void __user *)args->objects, process_bucket, args->objects_size); > + if (ret) { > + pr_err("Failed to copy process information to user\n"); > + ret = -EFAULT; > + } > + > + kfree(process_bucket); > + return ret; > +} > + > uint64_t get_process_num_bos(struct kfd_process *p) > { > uint64_t num_of_bos = 0, i; > @@ -1824,12 +1863,151 @@ uint64_t get_process_num_bos(struct kfd_process *p) > return num_of_bos; > } > > +static int criu_dump_bos(struct kfd_process *p, struct kfd_ioctl_criu_dumper_args *args) > +{ > + struct kfd_criu_bo_bucket *bo_buckets; > + struct kfd_criu_bo_priv_data *bo_privs; > + uint64_t num_bos; > + > + int ret = 0, pdd_index, bo_index = 0, id; > + void *mem; > + > + num_bos = get_process_num_bos(p); > + > + if (args->num_objects != num_bos) { > + pr_err("Mismatch with number of BOs (current:%lld user:%lld)\n", > + num_bos, args->num_objects); > + return -EINVAL; > + } > + > + if (args->objects_size != args->num_objects * (sizeof(*bo_buckets) + sizeof(*bo_privs))) { > + pr_err("Invalid objects size for BOs\n"); > + return -EINVAL; > + } > + > + bo_buckets = kvzalloc(args->objects_size, GFP_KERNEL); > + if (!bo_buckets) > + return -ENOMEM; > + > + /* Private data for first BO starts after all bo_buckets */ > + bo_privs = (void *)(bo_buckets + args->num_objects); > + > + for (pdd_index = 0; pdd_index < p->n_pdds; pdd_index++) { > + struct kfd_process_device *pdd = p->pdds[pdd_index]; > + struct amdgpu_bo *dumper_bo; > + struct kgd_mem *kgd_mem; > + > + idr_for_each_entry(&pdd->alloc_idr, mem, id) { > + struct kfd_criu_bo_bucket *bo_bucket; > + struct kfd_criu_bo_priv_data *bo_priv; > + > + if (!mem) { > + ret = -ENOMEM; > + goto exit; > + } > + > + kgd_mem = (struct kgd_mem *)mem; > + dumper_bo = kgd_mem->bo; > + > + if ((uint64_t)kgd_mem->va <= pdd->gpuvm_base) > + continue; > + > + bo_bucket = &bo_buckets[bo_index]; > + bo_priv = &bo_privs[bo_index]; > + > + bo_bucket->addr = (uint64_t)kgd_mem->va; > + bo_bucket->size = amdgpu_bo_size(dumper_bo); > + bo_bucket->gpu_id = pdd->dev->id; > + bo_bucket->alloc_flags = (uint32_t)kgd_mem->alloc_flags; > + > + bo_bucket->priv_data_offset = bo_index * sizeof(*bo_priv); > + bo_bucket->priv_data_size = sizeof(*bo_priv); > + > + bo_priv->idr_handle = id; > + if (bo_bucket->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR) { > + ret = amdgpu_ttm_tt_get_userptr(&dumper_bo->tbo, > + &bo_priv->user_addr); > + if (ret) { > + pr_err("Failed to obtain user address for user-pointer bo\n"); > + goto exit; > + } > + } > + if (bo_bucket->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL) > + bo_bucket->offset = KFD_MMAP_TYPE_DOORBELL | > + KFD_MMAP_GPU_ID(pdd->dev->id); > + else if (bo_bucket->alloc_flags & > + KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP) > + bo_bucket->offset = KFD_MMAP_TYPE_MMIO | > + KFD_MMAP_GPU_ID(pdd->dev->id); > + else > + bo_bucket->offset = amdgpu_bo_mmap_offset(dumper_bo); > + > + pr_debug("bo_size = 0x%llx, bo_addr = 0x%llx bo_offset = 0x%llx\n" > + "gpu_id = 0x%x alloc_flags = 0x%x idr_handle = 0x%x", > + bo_bucket->size, > + bo_bucket->addr, > + bo_bucket->offset, > + bo_bucket->gpu_id, > + bo_bucket->alloc_flags, > + bo_priv->idr_handle); > + bo_index++; > + } > + } > + > + ret = copy_to_user((void __user *)args->objects, bo_buckets, args->objects_size); > + if (ret) { > + pr_err("Failed to copy bo information to user\n"); > + ret = -EFAULT; > + } > + > +exit: > + kvfree(bo_buckets); > + return ret; > +} > + > static int kfd_ioctl_criu_dumper(struct file *filep, > struct kfd_process *p, void *data) > { > - pr_debug("Inside %s\n", __func__); > + struct kfd_ioctl_criu_dumper_args *args = data; > + int ret; > > - return 0; > + pr_debug("CRIU dump type:%d\n", args->type); > + > + if (!args->objects || !args->objects_size) > + return -EINVAL; > + > + mutex_lock(&p->mutex); > + > + if (!kfd_has_process_device_data(p)) { > + pr_err("No pdd for given process\n"); > + ret = -ENODEV; > + goto err_unlock; > + } > + > + switch (args->type) { > + case KFD_CRIU_OBJECT_TYPE_PROCESS: > + ret = criu_dump_process(p, args); > + break; > + case KFD_CRIU_OBJECT_TYPE_BO: > + ret = criu_dump_bos(p, args); > + break; > + case KFD_CRIU_OBJECT_TYPE_QUEUE: > + case KFD_CRIU_OBJECT_TYPE_EVENT: > + case KFD_CRIU_OBJECT_TYPE_DEVICE: > + case KFD_CRIU_OBJECT_TYPE_SVM_RANGE: > + default: > + pr_err("Unsupported object type:%d\n", args->type); > + ret = -EINVAL; > + } > + > +err_unlock: > + mutex_unlock(&p->mutex); > + if (ret) > + pr_err("Failed to dump CRIU type:%d ret:%d\n", args->type, ret); > + else > + pr_debug("CRIU dump type:%d ret:%d\n", args->type, ret); > + > + return ret; > } > > static int kfd_ioctl_criu_restorer(struct file *filep, > diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h > index 4e390006b4b6..8c9f2b3ac85d 100644 > --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h > +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h > @@ -1031,7 +1031,8 @@ struct kfd_criu_device_priv_data { > }; > > struct kfd_criu_bo_priv_data { > - uint64_t reserved; > + uint64_t user_addr; > + uint32_t idr_handle; > }; > > struct kfd_criu_svm_range_priv_data {