Implement the .retrieve_into() file handler API for memfd/shmem files. This implementation uses the standalone logic extracted previously to securely drop physical memory into an empty target inode.
Userspace topology delegation requires injecting folios into existing file descriptors. This implementation verifies the target descriptor is a shmem file and strictly guarantees it is empty before locking the inode and bridging the KHO folios into its address space. Signed-off-by: David Matlack <[email protected]> --- mm/memfd_luo.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c index 59de210bee5f..dcda5bf98646 100644 --- a/mm/memfd_luo.c +++ b/mm/memfd_luo.c @@ -590,10 +590,58 @@ static unsigned long memfd_luo_get_id(struct file *file) return (unsigned long)file_inode(file); } +static int memfd_luo_retrieve_into(struct liveupdate_file_op_args *args, struct file *target_file) +{ + struct inode *inode = file_inode(target_file); + struct memfd_luo_folio_ser *folios_ser; + struct memfd_luo_ser *ser; + int err; + + /* Security/Safety checks: Ensure it's a shmem file and is completely empty */ + if (!shmem_mapping(target_file->f_mapping)) + return -EINVAL; + + inode_lock(inode); + if (i_size_read(inode) != 0) { + inode_unlock(inode); + return -EBUSY; + } + + ser = phys_to_virt(args->serialized_data); + if (!ser) { + inode_unlock(inode); + return -EINVAL; + } + + if (ser->nr_folios) { + folios_ser = kho_restore_vmalloc(&ser->folios); + if (!folios_ser) { + inode_unlock(inode); + return -EINVAL; + } + + /* Inject the physical pages from KHO using the extracted helper */ + err = memfd_luo_retrieve_folios(target_file, folios_ser, ser->nr_folios); + kho_restore_free(folios_ser); + if (err) { + inode_unlock(inode); + return err; + } + } + + /* Fast-forward the kernel inode size to match the injected data */ + vfs_setpos(target_file, ser->pos, MAX_LFS_FILESIZE); + i_size_write(inode, ser->size); + + inode_unlock(inode); + return 0; +} + static const struct liveupdate_file_ops memfd_luo_file_ops = { .freeze = memfd_luo_freeze, .finish = memfd_luo_finish, .retrieve = memfd_luo_retrieve, + .retrieve_into = memfd_luo_retrieve_into, .preserve = memfd_luo_preserve, .unpreserve = memfd_luo_unpreserve, .can_preserve = memfd_luo_can_preserve, -- 2.55.0.966.g6673acef38-goog

