Re: [PATCH V3 vfio 5/7] vfio/virtio: Add support for the basic live migration functionality

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 12 Nov 2024 10:37:27 +0200
Yishai Hadas <yishaih@xxxxxxxxxx> wrote:
> diff --git a/drivers/vfio/pci/virtio/migrate.c b/drivers/vfio/pci/virtio/migrate.c
> new file mode 100644
> index 000000000000..3d5eaa1cbcdb
> --- /dev/null
> +++ b/drivers/vfio/pci/virtio/migrate.c
...
> +static int virtiovf_add_migration_pages(struct virtiovf_data_buffer *buf,
> +					unsigned int npages)
> +{
> +	unsigned int to_alloc = npages;
> +	struct page **page_list;
> +	unsigned long filled;
> +	unsigned int to_fill;
> +	int ret;
> +
> +	to_fill = min_t(unsigned int, npages, PAGE_SIZE / sizeof(*page_list));
> +	page_list = kvzalloc(to_fill * sizeof(*page_list), GFP_KERNEL_ACCOUNT);
> +	if (!page_list)
> +		return -ENOMEM;
> +
> +	do {
> +		filled = alloc_pages_bulk_array(GFP_KERNEL_ACCOUNT, to_fill,
> +						page_list);
> +		if (!filled) {
> +			ret = -ENOMEM;
> +			goto err;
> +		}
> +		to_alloc -= filled;
> +		ret = sg_alloc_append_table_from_pages(&buf->table, page_list,
> +			filled, 0, filled << PAGE_SHIFT, UINT_MAX,
> +			SG_MAX_SINGLE_ALLOC, GFP_KERNEL_ACCOUNT);
> +
> +		if (ret)
> +			goto err;

Cleanup here has me a bit concerned.  I see this pattern in
mlx5vf_add_migration_pages() as well.  IIUC, if we hit the previous
ENOMEM condition we simply free page_list and return error because any
pages we've already added to the sg table will be freed in the next
function below.  But what happens here?  It looks like we've allocated
a bunch of pages, failed to added them to the sg table and we drop them
on the floor.  Am I wrong?

> +		buf->allocated_length += filled * PAGE_SIZE;
> +		/* clean input for another bulk allocation */
> +		memset(page_list, 0, filled * sizeof(*page_list));
> +		to_fill = min_t(unsigned int, to_alloc,
> +				PAGE_SIZE / sizeof(*page_list));
> +	} while (to_alloc > 0);
> +
> +	kvfree(page_list);
> +	return 0;
> +
> +err:
> +	kvfree(page_list);
> +	return ret;

If ret were initialized to zero it looks like we wouldn't need
duplicate code for the success path, but that might change if we need
more unwind for the above.  Thanks,

Alex

> +}
> +
> +static void virtiovf_free_data_buffer(struct virtiovf_data_buffer *buf)
> +{
> +	struct sg_page_iter sg_iter;
> +
> +	/* Undo alloc_pages_bulk_array() */
> +	for_each_sgtable_page(&buf->table.sgt, &sg_iter, 0)
> +		__free_page(sg_page_iter_page(&sg_iter));
> +	sg_free_append_table(&buf->table);
> +	kfree(buf);
> +}





[Index of Archives]     [KVM Development]     [Libvirt Development]     [Libvirt Users]     [CentOS Virtualization]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux