Commit 35e884f8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-linus-5.8b-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull xen fixes from Juergen Gross:
 "One small cleanup patch for ARM and two patches for the xenbus driver
  fixing latent problems (large stack allocations and bad return code
  settings)"

* tag 'for-linus-5.8b-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen/xenbus: let xenbus_map_ring_valloc() return errno values only
  xen/xenbus: avoid large structs and arrays on the stack
  arm/xen: remove the unused macro GRANT_TABLE_PHYSADDR
parents 8b082a41 578c1bb9
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -241,7 +241,6 @@ static int __init fdt_find_hyper_node(unsigned long node, const char *uname,
 * see Documentation/devicetree/bindings/arm/xen.txt for the
 * documentation of the Xen Device Tree format.
 */
#define GRANT_TABLE_PHYSADDR 0
void __init xen_early_init(void)
{
	of_scan_flat_dt(fdt_find_hyper_node, NULL);
+81 −86
Original line number Diff line number Diff line
@@ -69,11 +69,27 @@ struct xenbus_map_node {
	unsigned int   nr_handles;
};

struct map_ring_valloc {
	struct xenbus_map_node *node;

	/* Why do we need two arrays? See comment of __xenbus_map_ring */
	union {
		unsigned long addrs[XENBUS_MAX_RING_GRANTS];
		pte_t *ptes[XENBUS_MAX_RING_GRANTS];
	};
	phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS];

	struct gnttab_map_grant_ref map[XENBUS_MAX_RING_GRANTS];
	struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS];

	unsigned int idx;	/* HVM only. */
};

static DEFINE_SPINLOCK(xenbus_valloc_lock);
static LIST_HEAD(xenbus_valloc_pages);

struct xenbus_ring_ops {
	int (*map)(struct xenbus_device *dev,
	int (*map)(struct xenbus_device *dev, struct map_ring_valloc *info,
		   grant_ref_t *gnt_refs, unsigned int nr_grefs,
		   void **vaddr);
	int (*unmap)(struct xenbus_device *dev, void *vaddr);
@@ -440,8 +456,7 @@ EXPORT_SYMBOL_GPL(xenbus_free_evtchn);
 * Map @nr_grefs pages of memory into this domain from another
 * domain's grant table.  xenbus_map_ring_valloc allocates @nr_grefs
 * pages of virtual address space, maps the pages to that address, and
 * sets *vaddr to that address.  Returns 0 on success, and GNTST_*
 * (see xen/include/interface/grant_table.h) or -ENOMEM / -EINVAL on
 * sets *vaddr to that address.  Returns 0 on success, and -errno on
 * error. If an error is returned, device will switch to
 * XenbusStateClosing and the error message will be saved in XenStore.
 */
@@ -449,12 +464,25 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs,
			   unsigned int nr_grefs, void **vaddr)
{
	int err;
	struct map_ring_valloc *info;

	*vaddr = NULL;

	err = ring_ops->map(dev, gnt_refs, nr_grefs, vaddr);
	/* Some hypervisors are buggy and can return 1. */
	if (err > 0)
		err = GNTST_general_error;
	if (nr_grefs > XENBUS_MAX_RING_GRANTS)
		return -EINVAL;

	info = kzalloc(sizeof(*info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	info->node = kzalloc(sizeof(*info->node), GFP_KERNEL);
	if (!info->node)
		err = -ENOMEM;
	else
		err = ring_ops->map(dev, info, gnt_refs, nr_grefs, vaddr);

	kfree(info->node);
	kfree(info);
	return err;
}
EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc);
@@ -466,62 +494,57 @@ static int __xenbus_map_ring(struct xenbus_device *dev,
			     grant_ref_t *gnt_refs,
			     unsigned int nr_grefs,
			     grant_handle_t *handles,
			     phys_addr_t *addrs,
			     struct map_ring_valloc *info,
			     unsigned int flags,
			     bool *leaked)
{
	struct gnttab_map_grant_ref map[XENBUS_MAX_RING_GRANTS];
	struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS];
	int i, j;
	int err = GNTST_okay;

	if (nr_grefs > XENBUS_MAX_RING_GRANTS)
		return -EINVAL;

	for (i = 0; i < nr_grefs; i++) {
		memset(&map[i], 0, sizeof(map[i]));
		gnttab_set_map_op(&map[i], addrs[i], flags, gnt_refs[i],
				  dev->otherend_id);
		gnttab_set_map_op(&info->map[i], info->phys_addrs[i], flags,
				  gnt_refs[i], dev->otherend_id);
		handles[i] = INVALID_GRANT_HANDLE;
	}

	gnttab_batch_map(map, i);
	gnttab_batch_map(info->map, i);

	for (i = 0; i < nr_grefs; i++) {
		if (map[i].status != GNTST_okay) {
			err = map[i].status;
			xenbus_dev_fatal(dev, map[i].status,
		if (info->map[i].status != GNTST_okay) {
			xenbus_dev_fatal(dev, info->map[i].status,
					 "mapping in shared page %d from domain %d",
					 gnt_refs[i], dev->otherend_id);
			goto fail;
		} else
			handles[i] = map[i].handle;
			handles[i] = info->map[i].handle;
	}

	return GNTST_okay;
	return 0;

 fail:
	for (i = j = 0; i < nr_grefs; i++) {
		if (handles[i] != INVALID_GRANT_HANDLE) {
			memset(&unmap[j], 0, sizeof(unmap[j]));
			gnttab_set_unmap_op(&unmap[j], (phys_addr_t)addrs[i],
			gnttab_set_unmap_op(&info->unmap[j],
					    info->phys_addrs[i],
					    GNTMAP_host_map, handles[i]);
			j++;
		}
	}

	if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, j))
	if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, info->unmap, j))
		BUG();

	*leaked = false;
	for (i = 0; i < j; i++) {
		if (unmap[i].status != GNTST_okay) {
		if (info->unmap[i].status != GNTST_okay) {
			*leaked = true;
			break;
		}
	}

	return err;
	return -ENOENT;
}

/**
@@ -566,21 +589,12 @@ static int xenbus_unmap_ring(struct xenbus_device *dev, grant_handle_t *handles,
	return err;
}

struct map_ring_valloc_hvm
{
	unsigned int idx;

	/* Why do we need two arrays? See comment of __xenbus_map_ring */
	phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS];
	unsigned long addrs[XENBUS_MAX_RING_GRANTS];
};

static void xenbus_map_ring_setup_grant_hvm(unsigned long gfn,
					    unsigned int goffset,
					    unsigned int len,
					    void *data)
{
	struct map_ring_valloc_hvm *info = data;
	struct map_ring_valloc *info = data;
	unsigned long vaddr = (unsigned long)gfn_to_virt(gfn);

	info->phys_addrs[info->idx] = vaddr;
@@ -589,39 +603,28 @@ static void xenbus_map_ring_setup_grant_hvm(unsigned long gfn,
	info->idx++;
}

static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev,
static int xenbus_map_ring_hvm(struct xenbus_device *dev,
			       struct map_ring_valloc *info,
			       grant_ref_t *gnt_ref,
			       unsigned int nr_grefs,
			       void **vaddr)
{
	struct xenbus_map_node *node;
	struct xenbus_map_node *node = info->node;
	int err;
	void *addr;
	bool leaked = false;
	struct map_ring_valloc_hvm info = {
		.idx = 0,
	};
	unsigned int nr_pages = XENBUS_PAGES(nr_grefs);

	if (nr_grefs > XENBUS_MAX_RING_GRANTS)
		return -EINVAL;

	*vaddr = NULL;

	node = kzalloc(sizeof(*node), GFP_KERNEL);
	if (!node)
		return -ENOMEM;

	err = alloc_xenballooned_pages(nr_pages, node->hvm.pages);
	if (err)
		goto out_err;

	gnttab_foreach_grant(node->hvm.pages, nr_grefs,
			     xenbus_map_ring_setup_grant_hvm,
			     &info);
			     info);

	err = __xenbus_map_ring(dev, gnt_ref, nr_grefs, node->handles,
				info.phys_addrs, GNTMAP_host_map, &leaked);
				info, GNTMAP_host_map, &leaked);
	node->nr_handles = nr_grefs;

	if (err)
@@ -641,11 +644,13 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev,
	spin_unlock(&xenbus_valloc_lock);

	*vaddr = addr;
	info->node = NULL;

	return 0;

 out_xenbus_unmap_ring:
	if (!leaked)
		xenbus_unmap_ring(dev, node->handles, nr_grefs, info.addrs);
		xenbus_unmap_ring(dev, node->handles, nr_grefs, info->addrs);
	else
		pr_alert("leaking %p size %u page(s)",
			 addr, nr_pages);
@@ -653,7 +658,6 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev,
	if (!leaked)
		free_xenballooned_pages(nr_pages, node->hvm.pages);
 out_err:
	kfree(node);
	return err;
}

@@ -676,40 +680,30 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree);

#ifdef CONFIG_XEN_PV
static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev,
static int xenbus_map_ring_pv(struct xenbus_device *dev,
			      struct map_ring_valloc *info,
			      grant_ref_t *gnt_refs,
			      unsigned int nr_grefs,
			      void **vaddr)
{
	struct xenbus_map_node *node;
	struct xenbus_map_node *node = info->node;
	struct vm_struct *area;
	pte_t *ptes[XENBUS_MAX_RING_GRANTS];
	phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS];
	int err = GNTST_okay;
	int i;
	bool leaked;

	*vaddr = NULL;

	if (nr_grefs > XENBUS_MAX_RING_GRANTS)
		return -EINVAL;

	node = kzalloc(sizeof(*node), GFP_KERNEL);
	if (!node)
		return -ENOMEM;

	area = alloc_vm_area(XEN_PAGE_SIZE * nr_grefs, ptes);
	area = alloc_vm_area(XEN_PAGE_SIZE * nr_grefs, info->ptes);
	if (!area) {
		kfree(node);
		return -ENOMEM;
	}

	for (i = 0; i < nr_grefs; i++)
		phys_addrs[i] = arbitrary_virt_to_machine(ptes[i]).maddr;
		info->phys_addrs[i] =
			arbitrary_virt_to_machine(info->ptes[i]).maddr;

	err = __xenbus_map_ring(dev, gnt_refs, nr_grefs, node->handles,
				phys_addrs,
				GNTMAP_host_map | GNTMAP_contains_pte,
				info, GNTMAP_host_map | GNTMAP_contains_pte,
				&leaked);
	if (err)
		goto failed;
@@ -722,6 +716,8 @@ static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev,
	spin_unlock(&xenbus_valloc_lock);

	*vaddr = area->addr;
	info->node = NULL;

	return 0;

failed:
@@ -730,11 +726,10 @@ failed:
	else
		pr_alert("leaking VM area %p size %u page(s)", area, nr_grefs);

	kfree(node);
	return err;
}

static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr)
static int xenbus_unmap_ring_pv(struct xenbus_device *dev, void *vaddr)
{
	struct xenbus_map_node *node;
	struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS];
@@ -798,12 +793,12 @@ static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr)
}

static const struct xenbus_ring_ops ring_ops_pv = {
	.map = xenbus_map_ring_valloc_pv,
	.unmap = xenbus_unmap_ring_vfree_pv,
	.map = xenbus_map_ring_pv,
	.unmap = xenbus_unmap_ring_pv,
};
#endif

struct unmap_ring_vfree_hvm
struct unmap_ring_hvm
{
	unsigned int idx;
	unsigned long addrs[XENBUS_MAX_RING_GRANTS];
@@ -814,19 +809,19 @@ static void xenbus_unmap_ring_setup_grant_hvm(unsigned long gfn,
					      unsigned int len,
					      void *data)
{
	struct unmap_ring_vfree_hvm *info = data;
	struct unmap_ring_hvm *info = data;

	info->addrs[info->idx] = (unsigned long)gfn_to_virt(gfn);

	info->idx++;
}

static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr)
static int xenbus_unmap_ring_hvm(struct xenbus_device *dev, void *vaddr)
{
	int rv;
	struct xenbus_map_node *node;
	void *addr;
	struct unmap_ring_vfree_hvm info = {
	struct unmap_ring_hvm info = {
		.idx = 0,
	};
	unsigned int nr_pages;
@@ -887,8 +882,8 @@ enum xenbus_state xenbus_read_driver_state(const char *path)
EXPORT_SYMBOL_GPL(xenbus_read_driver_state);

static const struct xenbus_ring_ops ring_ops_hvm = {
	.map = xenbus_map_ring_valloc_hvm,
	.unmap = xenbus_unmap_ring_vfree_hvm,
	.map = xenbus_map_ring_hvm,
	.unmap = xenbus_unmap_ring_hvm,
};

void __init xenbus_ring_ops_init(void)