| .. | .. |
|---|
| 69 | 69 | unsigned int nr_handles; |
|---|
| 70 | 70 | }; |
|---|
| 71 | 71 | |
|---|
| 72 | +struct map_ring_valloc { |
|---|
| 73 | + struct xenbus_map_node *node; |
|---|
| 74 | + |
|---|
| 75 | + /* Why do we need two arrays? See comment of __xenbus_map_ring */ |
|---|
| 76 | + unsigned long addrs[XENBUS_MAX_RING_GRANTS]; |
|---|
| 77 | + phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS]; |
|---|
| 78 | + |
|---|
| 79 | + struct gnttab_map_grant_ref map[XENBUS_MAX_RING_GRANTS]; |
|---|
| 80 | + struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS]; |
|---|
| 81 | + |
|---|
| 82 | + unsigned int idx; |
|---|
| 83 | +}; |
|---|
| 84 | + |
|---|
| 72 | 85 | static DEFINE_SPINLOCK(xenbus_valloc_lock); |
|---|
| 73 | 86 | static LIST_HEAD(xenbus_valloc_pages); |
|---|
| 74 | 87 | |
|---|
| 75 | 88 | struct xenbus_ring_ops { |
|---|
| 76 | | - int (*map)(struct xenbus_device *dev, |
|---|
| 89 | + int (*map)(struct xenbus_device *dev, struct map_ring_valloc *info, |
|---|
| 77 | 90 | grant_ref_t *gnt_refs, unsigned int nr_grefs, |
|---|
| 78 | 91 | void **vaddr); |
|---|
| 79 | 92 | int (*unmap)(struct xenbus_device *dev, void *vaddr); |
|---|
| .. | .. |
|---|
| 284 | 297 | dev_err(&dev->dev, "%s\n", printf_buffer); |
|---|
| 285 | 298 | |
|---|
| 286 | 299 | path_buffer = kasprintf(GFP_KERNEL, "error/%s", dev->nodename); |
|---|
| 287 | | - if (!path_buffer || |
|---|
| 288 | | - xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer)) |
|---|
| 289 | | - dev_err(&dev->dev, "failed to write error node for %s (%s)\n", |
|---|
| 290 | | - dev->nodename, printf_buffer); |
|---|
| 300 | + if (path_buffer) |
|---|
| 301 | + xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer); |
|---|
| 291 | 302 | |
|---|
| 292 | 303 | kfree(printf_buffer); |
|---|
| 293 | 304 | kfree(path_buffer); |
|---|
| .. | .. |
|---|
| 368 | 379 | unsigned int nr_pages, grant_ref_t *grefs) |
|---|
| 369 | 380 | { |
|---|
| 370 | 381 | int err; |
|---|
| 371 | | - int i, j; |
|---|
| 382 | + unsigned int i; |
|---|
| 383 | + grant_ref_t gref_head; |
|---|
| 384 | + |
|---|
| 385 | + err = gnttab_alloc_grant_references(nr_pages, &gref_head); |
|---|
| 386 | + if (err) { |
|---|
| 387 | + xenbus_dev_fatal(dev, err, "granting access to ring page"); |
|---|
| 388 | + return err; |
|---|
| 389 | + } |
|---|
| 372 | 390 | |
|---|
| 373 | 391 | for (i = 0; i < nr_pages; i++) { |
|---|
| 374 | 392 | unsigned long gfn; |
|---|
| .. | .. |
|---|
| 378 | 396 | else |
|---|
| 379 | 397 | gfn = virt_to_gfn(vaddr); |
|---|
| 380 | 398 | |
|---|
| 381 | | - err = gnttab_grant_foreign_access(dev->otherend_id, gfn, 0); |
|---|
| 382 | | - if (err < 0) { |
|---|
| 383 | | - xenbus_dev_fatal(dev, err, |
|---|
| 384 | | - "granting access to ring page"); |
|---|
| 385 | | - goto fail; |
|---|
| 386 | | - } |
|---|
| 387 | | - grefs[i] = err; |
|---|
| 399 | + grefs[i] = gnttab_claim_grant_reference(&gref_head); |
|---|
| 400 | + gnttab_grant_foreign_access_ref(grefs[i], dev->otherend_id, |
|---|
| 401 | + gfn, 0); |
|---|
| 388 | 402 | |
|---|
| 389 | 403 | vaddr = vaddr + XEN_PAGE_SIZE; |
|---|
| 390 | 404 | } |
|---|
| 391 | 405 | |
|---|
| 392 | 406 | return 0; |
|---|
| 393 | | - |
|---|
| 394 | | -fail: |
|---|
| 395 | | - for (j = 0; j < i; j++) |
|---|
| 396 | | - gnttab_end_foreign_access_ref(grefs[j], 0); |
|---|
| 397 | | - return err; |
|---|
| 398 | 407 | } |
|---|
| 399 | 408 | EXPORT_SYMBOL_GPL(xenbus_grant_ring); |
|---|
| 400 | 409 | |
|---|
| .. | .. |
|---|
| 405 | 414 | * error, the device will switch to XenbusStateClosing, and the error will be |
|---|
| 406 | 415 | * saved in the store. |
|---|
| 407 | 416 | */ |
|---|
| 408 | | -int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port) |
|---|
| 417 | +int xenbus_alloc_evtchn(struct xenbus_device *dev, evtchn_port_t *port) |
|---|
| 409 | 418 | { |
|---|
| 410 | 419 | struct evtchn_alloc_unbound alloc_unbound; |
|---|
| 411 | 420 | int err; |
|---|
| .. | .. |
|---|
| 428 | 437 | /** |
|---|
| 429 | 438 | * Free an existing event channel. Returns 0 on success or -errno on error. |
|---|
| 430 | 439 | */ |
|---|
| 431 | | -int xenbus_free_evtchn(struct xenbus_device *dev, int port) |
|---|
| 440 | +int xenbus_free_evtchn(struct xenbus_device *dev, evtchn_port_t port) |
|---|
| 432 | 441 | { |
|---|
| 433 | 442 | struct evtchn_close close; |
|---|
| 434 | 443 | int err; |
|---|
| .. | .. |
|---|
| 437 | 446 | |
|---|
| 438 | 447 | err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); |
|---|
| 439 | 448 | if (err) |
|---|
| 440 | | - xenbus_dev_error(dev, err, "freeing event channel %d", port); |
|---|
| 449 | + xenbus_dev_error(dev, err, "freeing event channel %u", port); |
|---|
| 441 | 450 | |
|---|
| 442 | 451 | return err; |
|---|
| 443 | 452 | } |
|---|
| .. | .. |
|---|
| 454 | 463 | * Map @nr_grefs pages of memory into this domain from another |
|---|
| 455 | 464 | * domain's grant table. xenbus_map_ring_valloc allocates @nr_grefs |
|---|
| 456 | 465 | * pages of virtual address space, maps the pages to that address, and |
|---|
| 457 | | - * sets *vaddr to that address. Returns 0 on success, and GNTST_* |
|---|
| 458 | | - * (see xen/include/interface/grant_table.h) or -ENOMEM / -EINVAL on |
|---|
| 466 | + * sets *vaddr to that address. Returns 0 on success, and -errno on |
|---|
| 459 | 467 | * error. If an error is returned, device will switch to |
|---|
| 460 | 468 | * XenbusStateClosing and the error message will be saved in XenStore. |
|---|
| 461 | 469 | */ |
|---|
| .. | .. |
|---|
| 463 | 471 | unsigned int nr_grefs, void **vaddr) |
|---|
| 464 | 472 | { |
|---|
| 465 | 473 | int err; |
|---|
| 474 | + struct map_ring_valloc *info; |
|---|
| 466 | 475 | |
|---|
| 467 | | - err = ring_ops->map(dev, gnt_refs, nr_grefs, vaddr); |
|---|
| 468 | | - /* Some hypervisors are buggy and can return 1. */ |
|---|
| 469 | | - if (err > 0) |
|---|
| 470 | | - err = GNTST_general_error; |
|---|
| 476 | + *vaddr = NULL; |
|---|
| 471 | 477 | |
|---|
| 478 | + if (nr_grefs > XENBUS_MAX_RING_GRANTS) |
|---|
| 479 | + return -EINVAL; |
|---|
| 480 | + |
|---|
| 481 | + info = kzalloc(sizeof(*info), GFP_KERNEL); |
|---|
| 482 | + if (!info) |
|---|
| 483 | + return -ENOMEM; |
|---|
| 484 | + |
|---|
| 485 | + info->node = kzalloc(sizeof(*info->node), GFP_KERNEL); |
|---|
| 486 | + if (!info->node) |
|---|
| 487 | + err = -ENOMEM; |
|---|
| 488 | + else |
|---|
| 489 | + err = ring_ops->map(dev, info, gnt_refs, nr_grefs, vaddr); |
|---|
| 490 | + |
|---|
| 491 | + kfree(info->node); |
|---|
| 492 | + kfree(info); |
|---|
| 472 | 493 | return err; |
|---|
| 473 | 494 | } |
|---|
| 474 | 495 | EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); |
|---|
| .. | .. |
|---|
| 480 | 501 | grant_ref_t *gnt_refs, |
|---|
| 481 | 502 | unsigned int nr_grefs, |
|---|
| 482 | 503 | grant_handle_t *handles, |
|---|
| 483 | | - phys_addr_t *addrs, |
|---|
| 504 | + struct map_ring_valloc *info, |
|---|
| 484 | 505 | unsigned int flags, |
|---|
| 485 | 506 | bool *leaked) |
|---|
| 486 | 507 | { |
|---|
| 487 | | - struct gnttab_map_grant_ref map[XENBUS_MAX_RING_GRANTS]; |
|---|
| 488 | | - struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS]; |
|---|
| 489 | 508 | int i, j; |
|---|
| 490 | | - int err = GNTST_okay; |
|---|
| 491 | 509 | |
|---|
| 492 | 510 | if (nr_grefs > XENBUS_MAX_RING_GRANTS) |
|---|
| 493 | 511 | return -EINVAL; |
|---|
| 494 | 512 | |
|---|
| 495 | 513 | for (i = 0; i < nr_grefs; i++) { |
|---|
| 496 | | - memset(&map[i], 0, sizeof(map[i])); |
|---|
| 497 | | - gnttab_set_map_op(&map[i], addrs[i], flags, gnt_refs[i], |
|---|
| 498 | | - dev->otherend_id); |
|---|
| 514 | + gnttab_set_map_op(&info->map[i], info->phys_addrs[i], flags, |
|---|
| 515 | + gnt_refs[i], dev->otherend_id); |
|---|
| 499 | 516 | handles[i] = INVALID_GRANT_HANDLE; |
|---|
| 500 | 517 | } |
|---|
| 501 | 518 | |
|---|
| 502 | | - gnttab_batch_map(map, i); |
|---|
| 519 | + gnttab_batch_map(info->map, i); |
|---|
| 503 | 520 | |
|---|
| 504 | 521 | for (i = 0; i < nr_grefs; i++) { |
|---|
| 505 | | - if (map[i].status != GNTST_okay) { |
|---|
| 506 | | - err = map[i].status; |
|---|
| 507 | | - xenbus_dev_fatal(dev, map[i].status, |
|---|
| 522 | + if (info->map[i].status != GNTST_okay) { |
|---|
| 523 | + xenbus_dev_fatal(dev, info->map[i].status, |
|---|
| 508 | 524 | "mapping in shared page %d from domain %d", |
|---|
| 509 | 525 | gnt_refs[i], dev->otherend_id); |
|---|
| 510 | 526 | goto fail; |
|---|
| 511 | 527 | } else |
|---|
| 512 | | - handles[i] = map[i].handle; |
|---|
| 528 | + handles[i] = info->map[i].handle; |
|---|
| 513 | 529 | } |
|---|
| 514 | 530 | |
|---|
| 515 | | - return GNTST_okay; |
|---|
| 531 | + return 0; |
|---|
| 516 | 532 | |
|---|
| 517 | 533 | fail: |
|---|
| 518 | 534 | for (i = j = 0; i < nr_grefs; i++) { |
|---|
| 519 | 535 | if (handles[i] != INVALID_GRANT_HANDLE) { |
|---|
| 520 | | - memset(&unmap[j], 0, sizeof(unmap[j])); |
|---|
| 521 | | - gnttab_set_unmap_op(&unmap[j], (phys_addr_t)addrs[i], |
|---|
| 536 | + gnttab_set_unmap_op(&info->unmap[j], |
|---|
| 537 | + info->phys_addrs[i], |
|---|
| 522 | 538 | GNTMAP_host_map, handles[i]); |
|---|
| 523 | 539 | j++; |
|---|
| 524 | 540 | } |
|---|
| 525 | 541 | } |
|---|
| 526 | 542 | |
|---|
| 527 | | - if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, j)) |
|---|
| 543 | + if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, info->unmap, j)) |
|---|
| 528 | 544 | BUG(); |
|---|
| 529 | 545 | |
|---|
| 530 | 546 | *leaked = false; |
|---|
| 531 | 547 | for (i = 0; i < j; i++) { |
|---|
| 532 | | - if (unmap[i].status != GNTST_okay) { |
|---|
| 548 | + if (info->unmap[i].status != GNTST_okay) { |
|---|
| 533 | 549 | *leaked = true; |
|---|
| 550 | + break; |
|---|
| 551 | + } |
|---|
| 552 | + } |
|---|
| 553 | + |
|---|
| 554 | + return -ENOENT; |
|---|
| 555 | +} |
|---|
| 556 | + |
|---|
| 557 | +/** |
|---|
| 558 | + * xenbus_unmap_ring |
|---|
| 559 | + * @dev: xenbus device |
|---|
| 560 | + * @handles: grant handle array |
|---|
| 561 | + * @nr_handles: number of handles in the array |
|---|
| 562 | + * @vaddrs: addresses to unmap |
|---|
| 563 | + * |
|---|
| 564 | + * Unmap memory in this domain that was imported from another domain. |
|---|
| 565 | + * Returns 0 on success and returns GNTST_* on error |
|---|
| 566 | + * (see xen/include/interface/grant_table.h). |
|---|
| 567 | + */ |
|---|
| 568 | +static int xenbus_unmap_ring(struct xenbus_device *dev, grant_handle_t *handles, |
|---|
| 569 | + unsigned int nr_handles, unsigned long *vaddrs) |
|---|
| 570 | +{ |
|---|
| 571 | + struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS]; |
|---|
| 572 | + int i; |
|---|
| 573 | + int err; |
|---|
| 574 | + |
|---|
| 575 | + if (nr_handles > XENBUS_MAX_RING_GRANTS) |
|---|
| 576 | + return -EINVAL; |
|---|
| 577 | + |
|---|
| 578 | + for (i = 0; i < nr_handles; i++) |
|---|
| 579 | + gnttab_set_unmap_op(&unmap[i], vaddrs[i], |
|---|
| 580 | + GNTMAP_host_map, handles[i]); |
|---|
| 581 | + |
|---|
| 582 | + if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, i)) |
|---|
| 583 | + BUG(); |
|---|
| 584 | + |
|---|
| 585 | + err = GNTST_okay; |
|---|
| 586 | + for (i = 0; i < nr_handles; i++) { |
|---|
| 587 | + if (unmap[i].status != GNTST_okay) { |
|---|
| 588 | + xenbus_dev_error(dev, unmap[i].status, |
|---|
| 589 | + "unmapping page at handle %d error %d", |
|---|
| 590 | + handles[i], unmap[i].status); |
|---|
| 591 | + err = unmap[i].status; |
|---|
| 534 | 592 | break; |
|---|
| 535 | 593 | } |
|---|
| 536 | 594 | } |
|---|
| .. | .. |
|---|
| 538 | 596 | return err; |
|---|
| 539 | 597 | } |
|---|
| 540 | 598 | |
|---|
| 541 | | -struct map_ring_valloc_hvm |
|---|
| 542 | | -{ |
|---|
| 543 | | - unsigned int idx; |
|---|
| 544 | | - |
|---|
| 545 | | - /* Why do we need two arrays? See comment of __xenbus_map_ring */ |
|---|
| 546 | | - phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS]; |
|---|
| 547 | | - unsigned long addrs[XENBUS_MAX_RING_GRANTS]; |
|---|
| 548 | | -}; |
|---|
| 549 | | - |
|---|
| 550 | 599 | static void xenbus_map_ring_setup_grant_hvm(unsigned long gfn, |
|---|
| 551 | 600 | unsigned int goffset, |
|---|
| 552 | 601 | unsigned int len, |
|---|
| 553 | 602 | void *data) |
|---|
| 554 | 603 | { |
|---|
| 555 | | - struct map_ring_valloc_hvm *info = data; |
|---|
| 604 | + struct map_ring_valloc *info = data; |
|---|
| 556 | 605 | unsigned long vaddr = (unsigned long)gfn_to_virt(gfn); |
|---|
| 557 | 606 | |
|---|
| 558 | 607 | info->phys_addrs[info->idx] = vaddr; |
|---|
| .. | .. |
|---|
| 561 | 610 | info->idx++; |
|---|
| 562 | 611 | } |
|---|
| 563 | 612 | |
|---|
| 564 | | -static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, |
|---|
| 565 | | - grant_ref_t *gnt_ref, |
|---|
| 566 | | - unsigned int nr_grefs, |
|---|
| 567 | | - void **vaddr) |
|---|
| 613 | +static int xenbus_map_ring_hvm(struct xenbus_device *dev, |
|---|
| 614 | + struct map_ring_valloc *info, |
|---|
| 615 | + grant_ref_t *gnt_ref, |
|---|
| 616 | + unsigned int nr_grefs, |
|---|
| 617 | + void **vaddr) |
|---|
| 568 | 618 | { |
|---|
| 569 | | - struct xenbus_map_node *node; |
|---|
| 619 | + struct xenbus_map_node *node = info->node; |
|---|
| 570 | 620 | int err; |
|---|
| 571 | 621 | void *addr; |
|---|
| 572 | 622 | bool leaked = false; |
|---|
| 573 | | - struct map_ring_valloc_hvm info = { |
|---|
| 574 | | - .idx = 0, |
|---|
| 575 | | - }; |
|---|
| 576 | 623 | unsigned int nr_pages = XENBUS_PAGES(nr_grefs); |
|---|
| 577 | 624 | |
|---|
| 578 | | - if (nr_grefs > XENBUS_MAX_RING_GRANTS) |
|---|
| 579 | | - return -EINVAL; |
|---|
| 580 | | - |
|---|
| 581 | | - *vaddr = NULL; |
|---|
| 582 | | - |
|---|
| 583 | | - node = kzalloc(sizeof(*node), GFP_KERNEL); |
|---|
| 584 | | - if (!node) |
|---|
| 585 | | - return -ENOMEM; |
|---|
| 586 | | - |
|---|
| 587 | | - err = alloc_xenballooned_pages(nr_pages, node->hvm.pages); |
|---|
| 625 | + err = xen_alloc_unpopulated_pages(nr_pages, node->hvm.pages); |
|---|
| 588 | 626 | if (err) |
|---|
| 589 | 627 | goto out_err; |
|---|
| 590 | 628 | |
|---|
| 591 | 629 | gnttab_foreach_grant(node->hvm.pages, nr_grefs, |
|---|
| 592 | 630 | xenbus_map_ring_setup_grant_hvm, |
|---|
| 593 | | - &info); |
|---|
| 631 | + info); |
|---|
| 594 | 632 | |
|---|
| 595 | 633 | err = __xenbus_map_ring(dev, gnt_ref, nr_grefs, node->handles, |
|---|
| 596 | | - info.phys_addrs, GNTMAP_host_map, &leaked); |
|---|
| 634 | + info, GNTMAP_host_map, &leaked); |
|---|
| 597 | 635 | node->nr_handles = nr_grefs; |
|---|
| 598 | 636 | |
|---|
| 599 | 637 | if (err) |
|---|
| .. | .. |
|---|
| 613 | 651 | spin_unlock(&xenbus_valloc_lock); |
|---|
| 614 | 652 | |
|---|
| 615 | 653 | *vaddr = addr; |
|---|
| 654 | + info->node = NULL; |
|---|
| 655 | + |
|---|
| 616 | 656 | return 0; |
|---|
| 617 | 657 | |
|---|
| 618 | 658 | out_xenbus_unmap_ring: |
|---|
| 619 | 659 | if (!leaked) |
|---|
| 620 | | - xenbus_unmap_ring(dev, node->handles, nr_grefs, info.addrs); |
|---|
| 660 | + xenbus_unmap_ring(dev, node->handles, nr_grefs, info->addrs); |
|---|
| 621 | 661 | else |
|---|
| 622 | 662 | pr_alert("leaking %p size %u page(s)", |
|---|
| 623 | 663 | addr, nr_pages); |
|---|
| 624 | 664 | out_free_ballooned_pages: |
|---|
| 625 | 665 | if (!leaked) |
|---|
| 626 | | - free_xenballooned_pages(nr_pages, node->hvm.pages); |
|---|
| 666 | + xen_free_unpopulated_pages(nr_pages, node->hvm.pages); |
|---|
| 627 | 667 | out_err: |
|---|
| 628 | | - kfree(node); |
|---|
| 629 | 668 | return err; |
|---|
| 630 | 669 | } |
|---|
| 631 | | - |
|---|
| 632 | | - |
|---|
| 633 | | -/** |
|---|
| 634 | | - * xenbus_map_ring |
|---|
| 635 | | - * @dev: xenbus device |
|---|
| 636 | | - * @gnt_refs: grant reference array |
|---|
| 637 | | - * @nr_grefs: number of grant reference |
|---|
| 638 | | - * @handles: pointer to grant handle to be filled |
|---|
| 639 | | - * @vaddrs: addresses to be mapped to |
|---|
| 640 | | - * @leaked: fail to clean up a failed map, caller should not free vaddr |
|---|
| 641 | | - * |
|---|
| 642 | | - * Map pages of memory into this domain from another domain's grant table. |
|---|
| 643 | | - * xenbus_map_ring does not allocate the virtual address space (you must do |
|---|
| 644 | | - * this yourself!). It only maps in the pages to the specified address. |
|---|
| 645 | | - * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) |
|---|
| 646 | | - * or -ENOMEM / -EINVAL on error. If an error is returned, device will switch to |
|---|
| 647 | | - * XenbusStateClosing and the first error message will be saved in XenStore. |
|---|
| 648 | | - * Further more if we fail to map the ring, caller should check @leaked. |
|---|
| 649 | | - * If @leaked is not zero it means xenbus_map_ring fails to clean up, caller |
|---|
| 650 | | - * should not free the address space of @vaddr. |
|---|
| 651 | | - */ |
|---|
| 652 | | -int xenbus_map_ring(struct xenbus_device *dev, grant_ref_t *gnt_refs, |
|---|
| 653 | | - unsigned int nr_grefs, grant_handle_t *handles, |
|---|
| 654 | | - unsigned long *vaddrs, bool *leaked) |
|---|
| 655 | | -{ |
|---|
| 656 | | - phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS]; |
|---|
| 657 | | - int i; |
|---|
| 658 | | - |
|---|
| 659 | | - if (nr_grefs > XENBUS_MAX_RING_GRANTS) |
|---|
| 660 | | - return -EINVAL; |
|---|
| 661 | | - |
|---|
| 662 | | - for (i = 0; i < nr_grefs; i++) |
|---|
| 663 | | - phys_addrs[i] = (unsigned long)vaddrs[i]; |
|---|
| 664 | | - |
|---|
| 665 | | - return __xenbus_map_ring(dev, gnt_refs, nr_grefs, handles, |
|---|
| 666 | | - phys_addrs, GNTMAP_host_map, leaked); |
|---|
| 667 | | -} |
|---|
| 668 | | -EXPORT_SYMBOL_GPL(xenbus_map_ring); |
|---|
| 669 | | - |
|---|
| 670 | 670 | |
|---|
| 671 | 671 | /** |
|---|
| 672 | 672 | * xenbus_unmap_ring_vfree |
|---|
| .. | .. |
|---|
| 687 | 687 | EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); |
|---|
| 688 | 688 | |
|---|
| 689 | 689 | #ifdef CONFIG_XEN_PV |
|---|
| 690 | | -static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, |
|---|
| 691 | | - grant_ref_t *gnt_refs, |
|---|
| 692 | | - unsigned int nr_grefs, |
|---|
| 693 | | - void **vaddr) |
|---|
| 690 | +static int map_ring_apply(pte_t *pte, unsigned long addr, void *data) |
|---|
| 694 | 691 | { |
|---|
| 695 | | - struct xenbus_map_node *node; |
|---|
| 692 | + struct map_ring_valloc *info = data; |
|---|
| 693 | + |
|---|
| 694 | + info->phys_addrs[info->idx++] = arbitrary_virt_to_machine(pte).maddr; |
|---|
| 695 | + return 0; |
|---|
| 696 | +} |
|---|
| 697 | + |
|---|
| 698 | +static int xenbus_map_ring_pv(struct xenbus_device *dev, |
|---|
| 699 | + struct map_ring_valloc *info, |
|---|
| 700 | + grant_ref_t *gnt_refs, |
|---|
| 701 | + unsigned int nr_grefs, |
|---|
| 702 | + void **vaddr) |
|---|
| 703 | +{ |
|---|
| 704 | + struct xenbus_map_node *node = info->node; |
|---|
| 696 | 705 | struct vm_struct *area; |
|---|
| 697 | | - pte_t *ptes[XENBUS_MAX_RING_GRANTS]; |
|---|
| 698 | | - phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS]; |
|---|
| 699 | | - int err = GNTST_okay; |
|---|
| 700 | | - int i; |
|---|
| 701 | | - bool leaked; |
|---|
| 706 | + bool leaked = false; |
|---|
| 707 | + int err = -ENOMEM; |
|---|
| 702 | 708 | |
|---|
| 703 | | - *vaddr = NULL; |
|---|
| 704 | | - |
|---|
| 705 | | - if (nr_grefs > XENBUS_MAX_RING_GRANTS) |
|---|
| 706 | | - return -EINVAL; |
|---|
| 707 | | - |
|---|
| 708 | | - node = kzalloc(sizeof(*node), GFP_KERNEL); |
|---|
| 709 | | - if (!node) |
|---|
| 709 | + area = get_vm_area(XEN_PAGE_SIZE * nr_grefs, VM_IOREMAP); |
|---|
| 710 | + if (!area) |
|---|
| 710 | 711 | return -ENOMEM; |
|---|
| 711 | | - |
|---|
| 712 | | - area = alloc_vm_area(XEN_PAGE_SIZE * nr_grefs, ptes); |
|---|
| 713 | | - if (!area) { |
|---|
| 714 | | - kfree(node); |
|---|
| 715 | | - return -ENOMEM; |
|---|
| 716 | | - } |
|---|
| 717 | | - |
|---|
| 718 | | - for (i = 0; i < nr_grefs; i++) |
|---|
| 719 | | - phys_addrs[i] = arbitrary_virt_to_machine(ptes[i]).maddr; |
|---|
| 720 | | - |
|---|
| 712 | + if (apply_to_page_range(&init_mm, (unsigned long)area->addr, |
|---|
| 713 | + XEN_PAGE_SIZE * nr_grefs, map_ring_apply, info)) |
|---|
| 714 | + goto failed; |
|---|
| 721 | 715 | err = __xenbus_map_ring(dev, gnt_refs, nr_grefs, node->handles, |
|---|
| 722 | | - phys_addrs, |
|---|
| 723 | | - GNTMAP_host_map | GNTMAP_contains_pte, |
|---|
| 716 | + info, GNTMAP_host_map | GNTMAP_contains_pte, |
|---|
| 724 | 717 | &leaked); |
|---|
| 725 | 718 | if (err) |
|---|
| 726 | 719 | goto failed; |
|---|
| .. | .. |
|---|
| 733 | 726 | spin_unlock(&xenbus_valloc_lock); |
|---|
| 734 | 727 | |
|---|
| 735 | 728 | *vaddr = area->addr; |
|---|
| 729 | + info->node = NULL; |
|---|
| 730 | + |
|---|
| 736 | 731 | return 0; |
|---|
| 737 | 732 | |
|---|
| 738 | 733 | failed: |
|---|
| .. | .. |
|---|
| 741 | 736 | else |
|---|
| 742 | 737 | pr_alert("leaking VM area %p size %u page(s)", area, nr_grefs); |
|---|
| 743 | 738 | |
|---|
| 744 | | - kfree(node); |
|---|
| 745 | 739 | return err; |
|---|
| 746 | 740 | } |
|---|
| 747 | 741 | |
|---|
| 748 | | -static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) |
|---|
| 742 | +static int xenbus_unmap_ring_pv(struct xenbus_device *dev, void *vaddr) |
|---|
| 749 | 743 | { |
|---|
| 750 | 744 | struct xenbus_map_node *node; |
|---|
| 751 | 745 | struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS]; |
|---|
| .. | .. |
|---|
| 809 | 803 | } |
|---|
| 810 | 804 | |
|---|
| 811 | 805 | static const struct xenbus_ring_ops ring_ops_pv = { |
|---|
| 812 | | - .map = xenbus_map_ring_valloc_pv, |
|---|
| 813 | | - .unmap = xenbus_unmap_ring_vfree_pv, |
|---|
| 806 | + .map = xenbus_map_ring_pv, |
|---|
| 807 | + .unmap = xenbus_unmap_ring_pv, |
|---|
| 814 | 808 | }; |
|---|
| 815 | 809 | #endif |
|---|
| 816 | 810 | |
|---|
| 817 | | -struct unmap_ring_vfree_hvm |
|---|
| 811 | +struct unmap_ring_hvm |
|---|
| 818 | 812 | { |
|---|
| 819 | 813 | unsigned int idx; |
|---|
| 820 | 814 | unsigned long addrs[XENBUS_MAX_RING_GRANTS]; |
|---|
| .. | .. |
|---|
| 825 | 819 | unsigned int len, |
|---|
| 826 | 820 | void *data) |
|---|
| 827 | 821 | { |
|---|
| 828 | | - struct unmap_ring_vfree_hvm *info = data; |
|---|
| 822 | + struct unmap_ring_hvm *info = data; |
|---|
| 829 | 823 | |
|---|
| 830 | 824 | info->addrs[info->idx] = (unsigned long)gfn_to_virt(gfn); |
|---|
| 831 | 825 | |
|---|
| 832 | 826 | info->idx++; |
|---|
| 833 | 827 | } |
|---|
| 834 | 828 | |
|---|
| 835 | | -static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) |
|---|
| 829 | +static int xenbus_unmap_ring_hvm(struct xenbus_device *dev, void *vaddr) |
|---|
| 836 | 830 | { |
|---|
| 837 | 831 | int rv; |
|---|
| 838 | 832 | struct xenbus_map_node *node; |
|---|
| 839 | 833 | void *addr; |
|---|
| 840 | | - struct unmap_ring_vfree_hvm info = { |
|---|
| 834 | + struct unmap_ring_hvm info = { |
|---|
| 841 | 835 | .idx = 0, |
|---|
| 842 | 836 | }; |
|---|
| 843 | 837 | unsigned int nr_pages; |
|---|
| .. | .. |
|---|
| 870 | 864 | info.addrs); |
|---|
| 871 | 865 | if (!rv) { |
|---|
| 872 | 866 | vunmap(vaddr); |
|---|
| 873 | | - free_xenballooned_pages(nr_pages, node->hvm.pages); |
|---|
| 867 | + xen_free_unpopulated_pages(nr_pages, node->hvm.pages); |
|---|
| 874 | 868 | } |
|---|
| 875 | 869 | else |
|---|
| 876 | 870 | WARN(1, "Leaking %p, size %u page(s)\n", vaddr, nr_pages); |
|---|
| .. | .. |
|---|
| 878 | 872 | kfree(node); |
|---|
| 879 | 873 | return rv; |
|---|
| 880 | 874 | } |
|---|
| 881 | | - |
|---|
| 882 | | -/** |
|---|
| 883 | | - * xenbus_unmap_ring |
|---|
| 884 | | - * @dev: xenbus device |
|---|
| 885 | | - * @handles: grant handle array |
|---|
| 886 | | - * @nr_handles: number of handles in the array |
|---|
| 887 | | - * @vaddrs: addresses to unmap |
|---|
| 888 | | - * |
|---|
| 889 | | - * Unmap memory in this domain that was imported from another domain. |
|---|
| 890 | | - * Returns 0 on success and returns GNTST_* on error |
|---|
| 891 | | - * (see xen/include/interface/grant_table.h). |
|---|
| 892 | | - */ |
|---|
| 893 | | -int xenbus_unmap_ring(struct xenbus_device *dev, |
|---|
| 894 | | - grant_handle_t *handles, unsigned int nr_handles, |
|---|
| 895 | | - unsigned long *vaddrs) |
|---|
| 896 | | -{ |
|---|
| 897 | | - struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS]; |
|---|
| 898 | | - int i; |
|---|
| 899 | | - int err; |
|---|
| 900 | | - |
|---|
| 901 | | - if (nr_handles > XENBUS_MAX_RING_GRANTS) |
|---|
| 902 | | - return -EINVAL; |
|---|
| 903 | | - |
|---|
| 904 | | - for (i = 0; i < nr_handles; i++) |
|---|
| 905 | | - gnttab_set_unmap_op(&unmap[i], vaddrs[i], |
|---|
| 906 | | - GNTMAP_host_map, handles[i]); |
|---|
| 907 | | - |
|---|
| 908 | | - if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, i)) |
|---|
| 909 | | - BUG(); |
|---|
| 910 | | - |
|---|
| 911 | | - err = GNTST_okay; |
|---|
| 912 | | - for (i = 0; i < nr_handles; i++) { |
|---|
| 913 | | - if (unmap[i].status != GNTST_okay) { |
|---|
| 914 | | - xenbus_dev_error(dev, unmap[i].status, |
|---|
| 915 | | - "unmapping page at handle %d error %d", |
|---|
| 916 | | - handles[i], unmap[i].status); |
|---|
| 917 | | - err = unmap[i].status; |
|---|
| 918 | | - break; |
|---|
| 919 | | - } |
|---|
| 920 | | - } |
|---|
| 921 | | - |
|---|
| 922 | | - return err; |
|---|
| 923 | | -} |
|---|
| 924 | | -EXPORT_SYMBOL_GPL(xenbus_unmap_ring); |
|---|
| 925 | | - |
|---|
| 926 | 875 | |
|---|
| 927 | 876 | /** |
|---|
| 928 | 877 | * xenbus_read_driver_state |
|---|
| .. | .. |
|---|
| 943 | 892 | EXPORT_SYMBOL_GPL(xenbus_read_driver_state); |
|---|
| 944 | 893 | |
|---|
| 945 | 894 | static const struct xenbus_ring_ops ring_ops_hvm = { |
|---|
| 946 | | - .map = xenbus_map_ring_valloc_hvm, |
|---|
| 947 | | - .unmap = xenbus_unmap_ring_vfree_hvm, |
|---|
| 895 | + .map = xenbus_map_ring_hvm, |
|---|
| 896 | + .unmap = xenbus_unmap_ring_hvm, |
|---|
| 948 | 897 | }; |
|---|
| 949 | 898 | |
|---|
| 950 | 899 | void __init xenbus_ring_ops_init(void) |
|---|