diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-10 13:09:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-10 13:09:59 -0500 |
commit | 90160371b3a3e67ef78d68210a94dd30664a703d (patch) | |
tree | 2841ea811be129133cf9b83d9c3badd96e7ffab4 /drivers/xen/xenbus | |
parent | ae5cfc0546ca2698b9dcddf72accbd70e57590a0 (diff) | |
parent | 6c254de16a1d14c1ac931d3aa08dc88ac9fc582b (diff) |
Merge branch 'stable/for-linus-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen
* 'stable/for-linus-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen: (37 commits)
xen/pciback: Expand the warning message to include domain id.
xen/pciback: Fix "device has been assigned to X domain!" warning
xen/pciback: Move the PCI_DEV_FLAGS_ASSIGNED ops to the "[un|]bind"
xen/xenbus: don't reimplement kvasprintf via a fixed size buffer
xenbus: maximum buffer size is XENSTORE_PAYLOAD_MAX
xen/xenbus: Reject replies with payload > XENSTORE_PAYLOAD_MAX.
Xen: consolidate and simplify struct xenbus_driver instantiation
xen-gntalloc: introduce missing kfree
xen/xenbus: Fix compile error - missing header for xen_initial_domain()
xen/netback: Enable netback on HVM guests
xen/grant-table: Support mappings required by blkback
xenbus: Use grant-table wrapper functions
xenbus: Support HVM backends
xen/xenbus-frontend: Fix compile error with randconfig
xen/xenbus-frontend: Make error message more clear
xen/privcmd: Remove unused support for arch specific privcmp mmap
xen: Add xenbus_backend device
xen: Add xenbus device driver
xen: Add privcmd device driver
xen/gntalloc: fix reference counts on multi-page mappings
...
Diffstat (limited to 'drivers/xen/xenbus')
-rw-r--r-- | drivers/xen/xenbus/Makefile | 2 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_client.c | 193 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_comms.h | 4 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_dev_backend.c | 90 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_dev_frontend.c | 625 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_probe.c | 9 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_probe.h | 6 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_probe_backend.c | 8 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_probe_frontend.c | 8 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_xs.c | 23 |
10 files changed, 908 insertions, 60 deletions
diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile index 8dca685358b4..31e2e9050c7a 100644 --- a/drivers/xen/xenbus/Makefile +++ b/drivers/xen/xenbus/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | obj-y += xenbus.o | 1 | obj-y += xenbus.o |
2 | obj-y += xenbus_dev_frontend.o | ||
2 | 3 | ||
3 | xenbus-objs = | 4 | xenbus-objs = |
4 | xenbus-objs += xenbus_client.o | 5 | xenbus-objs += xenbus_client.o |
@@ -9,4 +10,5 @@ xenbus-objs += xenbus_probe.o | |||
9 | xenbus-be-objs-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o | 10 | xenbus-be-objs-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o |
10 | xenbus-objs += $(xenbus-be-objs-y) | 11 | xenbus-objs += $(xenbus-be-objs-y) |
11 | 12 | ||
13 | obj-$(CONFIG_XEN_BACKEND) += xenbus_dev_backend.o | ||
12 | obj-$(CONFIG_XEN_XENBUS_FRONTEND) += xenbus_probe_frontend.o | 14 | obj-$(CONFIG_XEN_XENBUS_FRONTEND) += xenbus_probe_frontend.o |
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index 1906125eab49..566d2adbd6ea 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c | |||
@@ -32,15 +32,39 @@ | |||
32 | 32 | ||
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/types.h> | 34 | #include <linux/types.h> |
35 | #include <linux/spinlock.h> | ||
35 | #include <linux/vmalloc.h> | 36 | #include <linux/vmalloc.h> |
36 | #include <linux/export.h> | 37 | #include <linux/export.h> |
37 | #include <asm/xen/hypervisor.h> | 38 | #include <asm/xen/hypervisor.h> |
38 | #include <asm/xen/page.h> | 39 | #include <asm/xen/page.h> |
39 | #include <xen/interface/xen.h> | 40 | #include <xen/interface/xen.h> |
40 | #include <xen/interface/event_channel.h> | 41 | #include <xen/interface/event_channel.h> |
42 | #include <xen/balloon.h> | ||
41 | #include <xen/events.h> | 43 | #include <xen/events.h> |
42 | #include <xen/grant_table.h> | 44 | #include <xen/grant_table.h> |
43 | #include <xen/xenbus.h> | 45 | #include <xen/xenbus.h> |
46 | #include <xen/xen.h> | ||
47 | |||
48 | #include "xenbus_probe.h" | ||
49 | |||
50 | struct xenbus_map_node { | ||
51 | struct list_head next; | ||
52 | union { | ||
53 | struct vm_struct *area; /* PV */ | ||
54 | struct page *page; /* HVM */ | ||
55 | }; | ||
56 | grant_handle_t handle; | ||
57 | }; | ||
58 | |||
59 | static DEFINE_SPINLOCK(xenbus_valloc_lock); | ||
60 | static LIST_HEAD(xenbus_valloc_pages); | ||
61 | |||
62 | struct xenbus_ring_ops { | ||
63 | int (*map)(struct xenbus_device *dev, int gnt, void **vaddr); | ||
64 | int (*unmap)(struct xenbus_device *dev, void *vaddr); | ||
65 | }; | ||
66 | |||
67 | static const struct xenbus_ring_ops *ring_ops __read_mostly; | ||
44 | 68 | ||
45 | const char *xenbus_strstate(enum xenbus_state state) | 69 | const char *xenbus_strstate(enum xenbus_state state) |
46 | { | 70 | { |
@@ -436,19 +460,33 @@ EXPORT_SYMBOL_GPL(xenbus_free_evtchn); | |||
436 | */ | 460 | */ |
437 | int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) | 461 | int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) |
438 | { | 462 | { |
463 | return ring_ops->map(dev, gnt_ref, vaddr); | ||
464 | } | ||
465 | EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); | ||
466 | |||
467 | static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, | ||
468 | int gnt_ref, void **vaddr) | ||
469 | { | ||
439 | struct gnttab_map_grant_ref op = { | 470 | struct gnttab_map_grant_ref op = { |
440 | .flags = GNTMAP_host_map | GNTMAP_contains_pte, | 471 | .flags = GNTMAP_host_map | GNTMAP_contains_pte, |
441 | .ref = gnt_ref, | 472 | .ref = gnt_ref, |
442 | .dom = dev->otherend_id, | 473 | .dom = dev->otherend_id, |
443 | }; | 474 | }; |
475 | struct xenbus_map_node *node; | ||
444 | struct vm_struct *area; | 476 | struct vm_struct *area; |
445 | pte_t *pte; | 477 | pte_t *pte; |
446 | 478 | ||
447 | *vaddr = NULL; | 479 | *vaddr = NULL; |
448 | 480 | ||
481 | node = kzalloc(sizeof(*node), GFP_KERNEL); | ||
482 | if (!node) | ||
483 | return -ENOMEM; | ||
484 | |||
449 | area = alloc_vm_area(PAGE_SIZE, &pte); | 485 | area = alloc_vm_area(PAGE_SIZE, &pte); |
450 | if (!area) | 486 | if (!area) { |
487 | kfree(node); | ||
451 | return -ENOMEM; | 488 | return -ENOMEM; |
489 | } | ||
452 | 490 | ||
453 | op.host_addr = arbitrary_virt_to_machine(pte).maddr; | 491 | op.host_addr = arbitrary_virt_to_machine(pte).maddr; |
454 | 492 | ||
@@ -457,19 +495,59 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) | |||
457 | 495 | ||
458 | if (op.status != GNTST_okay) { | 496 | if (op.status != GNTST_okay) { |
459 | free_vm_area(area); | 497 | free_vm_area(area); |
498 | kfree(node); | ||
460 | xenbus_dev_fatal(dev, op.status, | 499 | xenbus_dev_fatal(dev, op.status, |
461 | "mapping in shared page %d from domain %d", | 500 | "mapping in shared page %d from domain %d", |
462 | gnt_ref, dev->otherend_id); | 501 | gnt_ref, dev->otherend_id); |
463 | return op.status; | 502 | return op.status; |
464 | } | 503 | } |
465 | 504 | ||
466 | /* Stuff the handle in an unused field */ | 505 | node->handle = op.handle; |
467 | area->phys_addr = (unsigned long)op.handle; | 506 | node->area = area; |
507 | |||
508 | spin_lock(&xenbus_valloc_lock); | ||
509 | list_add(&node->next, &xenbus_valloc_pages); | ||
510 | spin_unlock(&xenbus_valloc_lock); | ||
468 | 511 | ||
469 | *vaddr = area->addr; | 512 | *vaddr = area->addr; |
470 | return 0; | 513 | return 0; |
471 | } | 514 | } |
472 | EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); | 515 | |
516 | static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, | ||
517 | int gnt_ref, void **vaddr) | ||
518 | { | ||
519 | struct xenbus_map_node *node; | ||
520 | int err; | ||
521 | void *addr; | ||
522 | |||
523 | *vaddr = NULL; | ||
524 | |||
525 | node = kzalloc(sizeof(*node), GFP_KERNEL); | ||
526 | if (!node) | ||
527 | return -ENOMEM; | ||
528 | |||
529 | err = alloc_xenballooned_pages(1, &node->page, false /* lowmem */); | ||
530 | if (err) | ||
531 | goto out_err; | ||
532 | |||
533 | addr = pfn_to_kaddr(page_to_pfn(node->page)); | ||
534 | |||
535 | err = xenbus_map_ring(dev, gnt_ref, &node->handle, addr); | ||
536 | if (err) | ||
537 | goto out_err; | ||
538 | |||
539 | spin_lock(&xenbus_valloc_lock); | ||
540 | list_add(&node->next, &xenbus_valloc_pages); | ||
541 | spin_unlock(&xenbus_valloc_lock); | ||
542 | |||
543 | *vaddr = addr; | ||
544 | return 0; | ||
545 | |||
546 | out_err: | ||
547 | free_xenballooned_pages(1, &node->page); | ||
548 | kfree(node); | ||
549 | return err; | ||
550 | } | ||
473 | 551 | ||
474 | 552 | ||
475 | /** | 553 | /** |
@@ -489,12 +567,10 @@ EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); | |||
489 | int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, | 567 | int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, |
490 | grant_handle_t *handle, void *vaddr) | 568 | grant_handle_t *handle, void *vaddr) |
491 | { | 569 | { |
492 | struct gnttab_map_grant_ref op = { | 570 | struct gnttab_map_grant_ref op; |
493 | .host_addr = (unsigned long)vaddr, | 571 | |
494 | .flags = GNTMAP_host_map, | 572 | gnttab_set_map_op(&op, (phys_addr_t)vaddr, GNTMAP_host_map, gnt_ref, |
495 | .ref = gnt_ref, | 573 | dev->otherend_id); |
496 | .dom = dev->otherend_id, | ||
497 | }; | ||
498 | 574 | ||
499 | if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) | 575 | if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) |
500 | BUG(); | 576 | BUG(); |
@@ -525,32 +601,36 @@ EXPORT_SYMBOL_GPL(xenbus_map_ring); | |||
525 | */ | 601 | */ |
526 | int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) | 602 | int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) |
527 | { | 603 | { |
528 | struct vm_struct *area; | 604 | return ring_ops->unmap(dev, vaddr); |
605 | } | ||
606 | EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); | ||
607 | |||
608 | static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) | ||
609 | { | ||
610 | struct xenbus_map_node *node; | ||
529 | struct gnttab_unmap_grant_ref op = { | 611 | struct gnttab_unmap_grant_ref op = { |
530 | .host_addr = (unsigned long)vaddr, | 612 | .host_addr = (unsigned long)vaddr, |
531 | }; | 613 | }; |
532 | unsigned int level; | 614 | unsigned int level; |
533 | 615 | ||
534 | /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr) | 616 | spin_lock(&xenbus_valloc_lock); |
535 | * method so that we don't have to muck with vmalloc internals here. | 617 | list_for_each_entry(node, &xenbus_valloc_pages, next) { |
536 | * We could force the user to hang on to their struct vm_struct from | 618 | if (node->area->addr == vaddr) { |
537 | * xenbus_map_ring_valloc, but these 6 lines considerably simplify | 619 | list_del(&node->next); |
538 | * this API. | 620 | goto found; |
539 | */ | 621 | } |
540 | read_lock(&vmlist_lock); | ||
541 | for (area = vmlist; area != NULL; area = area->next) { | ||
542 | if (area->addr == vaddr) | ||
543 | break; | ||
544 | } | 622 | } |
545 | read_unlock(&vmlist_lock); | 623 | node = NULL; |
624 | found: | ||
625 | spin_unlock(&xenbus_valloc_lock); | ||
546 | 626 | ||
547 | if (!area) { | 627 | if (!node) { |
548 | xenbus_dev_error(dev, -ENOENT, | 628 | xenbus_dev_error(dev, -ENOENT, |
549 | "can't find mapped virtual address %p", vaddr); | 629 | "can't find mapped virtual address %p", vaddr); |
550 | return GNTST_bad_virt_addr; | 630 | return GNTST_bad_virt_addr; |
551 | } | 631 | } |
552 | 632 | ||
553 | op.handle = (grant_handle_t)area->phys_addr; | 633 | op.handle = node->handle; |
554 | op.host_addr = arbitrary_virt_to_machine( | 634 | op.host_addr = arbitrary_virt_to_machine( |
555 | lookup_address((unsigned long)vaddr, &level)).maddr; | 635 | lookup_address((unsigned long)vaddr, &level)).maddr; |
556 | 636 | ||
@@ -558,16 +638,50 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) | |||
558 | BUG(); | 638 | BUG(); |
559 | 639 | ||
560 | if (op.status == GNTST_okay) | 640 | if (op.status == GNTST_okay) |
561 | free_vm_area(area); | 641 | free_vm_area(node->area); |
562 | else | 642 | else |
563 | xenbus_dev_error(dev, op.status, | 643 | xenbus_dev_error(dev, op.status, |
564 | "unmapping page at handle %d error %d", | 644 | "unmapping page at handle %d error %d", |
565 | (int16_t)area->phys_addr, op.status); | 645 | node->handle, op.status); |
566 | 646 | ||
647 | kfree(node); | ||
567 | return op.status; | 648 | return op.status; |
568 | } | 649 | } |
569 | EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); | ||
570 | 650 | ||
651 | static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) | ||
652 | { | ||
653 | int rv; | ||
654 | struct xenbus_map_node *node; | ||
655 | void *addr; | ||
656 | |||
657 | spin_lock(&xenbus_valloc_lock); | ||
658 | list_for_each_entry(node, &xenbus_valloc_pages, next) { | ||
659 | addr = pfn_to_kaddr(page_to_pfn(node->page)); | ||
660 | if (addr == vaddr) { | ||
661 | list_del(&node->next); | ||
662 | goto found; | ||
663 | } | ||
664 | } | ||
665 | node = NULL; | ||
666 | found: | ||
667 | spin_unlock(&xenbus_valloc_lock); | ||
668 | |||
669 | if (!node) { | ||
670 | xenbus_dev_error(dev, -ENOENT, | ||
671 | "can't find mapped virtual address %p", vaddr); | ||
672 | return GNTST_bad_virt_addr; | ||
673 | } | ||
674 | |||
675 | rv = xenbus_unmap_ring(dev, node->handle, addr); | ||
676 | |||
677 | if (!rv) | ||
678 | free_xenballooned_pages(1, &node->page); | ||
679 | else | ||
680 | WARN(1, "Leaking %p\n", vaddr); | ||
681 | |||
682 | kfree(node); | ||
683 | return rv; | ||
684 | } | ||
571 | 685 | ||
572 | /** | 686 | /** |
573 | * xenbus_unmap_ring | 687 | * xenbus_unmap_ring |
@@ -582,10 +696,9 @@ EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); | |||
582 | int xenbus_unmap_ring(struct xenbus_device *dev, | 696 | int xenbus_unmap_ring(struct xenbus_device *dev, |
583 | grant_handle_t handle, void *vaddr) | 697 | grant_handle_t handle, void *vaddr) |
584 | { | 698 | { |
585 | struct gnttab_unmap_grant_ref op = { | 699 | struct gnttab_unmap_grant_ref op; |
586 | .host_addr = (unsigned long)vaddr, | 700 | |
587 | .handle = handle, | 701 | gnttab_set_unmap_op(&op, (phys_addr_t)vaddr, GNTMAP_host_map, handle); |
588 | }; | ||
589 | 702 | ||
590 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) | 703 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) |
591 | BUG(); | 704 | BUG(); |
@@ -617,3 +730,21 @@ enum xenbus_state xenbus_read_driver_state(const char *path) | |||
617 | return result; | 730 | return result; |
618 | } | 731 | } |
619 | EXPORT_SYMBOL_GPL(xenbus_read_driver_state); | 732 | EXPORT_SYMBOL_GPL(xenbus_read_driver_state); |
733 | |||
734 | static const struct xenbus_ring_ops ring_ops_pv = { | ||
735 | .map = xenbus_map_ring_valloc_pv, | ||
736 | .unmap = xenbus_unmap_ring_vfree_pv, | ||
737 | }; | ||
738 | |||
739 | static const struct xenbus_ring_ops ring_ops_hvm = { | ||
740 | .map = xenbus_map_ring_valloc_hvm, | ||
741 | .unmap = xenbus_unmap_ring_vfree_hvm, | ||
742 | }; | ||
743 | |||
744 | void __init xenbus_ring_ops_init(void) | ||
745 | { | ||
746 | if (xen_pv_domain()) | ||
747 | ring_ops = &ring_ops_pv; | ||
748 | else | ||
749 | ring_ops = &ring_ops_hvm; | ||
750 | } | ||
diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h index c21db7513736..6e42800fa499 100644 --- a/drivers/xen/xenbus/xenbus_comms.h +++ b/drivers/xen/xenbus/xenbus_comms.h | |||
@@ -31,6 +31,8 @@ | |||
31 | #ifndef _XENBUS_COMMS_H | 31 | #ifndef _XENBUS_COMMS_H |
32 | #define _XENBUS_COMMS_H | 32 | #define _XENBUS_COMMS_H |
33 | 33 | ||
34 | #include <linux/fs.h> | ||
35 | |||
34 | int xs_init(void); | 36 | int xs_init(void); |
35 | int xb_init_comms(void); | 37 | int xb_init_comms(void); |
36 | 38 | ||
@@ -43,4 +45,6 @@ int xs_input_avail(void); | |||
43 | extern struct xenstore_domain_interface *xen_store_interface; | 45 | extern struct xenstore_domain_interface *xen_store_interface; |
44 | extern int xen_store_evtchn; | 46 | extern int xen_store_evtchn; |
45 | 47 | ||
48 | extern const struct file_operations xen_xenbus_fops; | ||
49 | |||
46 | #endif /* _XENBUS_COMMS_H */ | 50 | #endif /* _XENBUS_COMMS_H */ |
diff --git a/drivers/xen/xenbus/xenbus_dev_backend.c b/drivers/xen/xenbus/xenbus_dev_backend.c new file mode 100644 index 000000000000..3d3be78c1093 --- /dev/null +++ b/drivers/xen/xenbus/xenbus_dev_backend.c | |||
@@ -0,0 +1,90 @@ | |||
1 | #include <linux/slab.h> | ||
2 | #include <linux/types.h> | ||
3 | #include <linux/mm.h> | ||
4 | #include <linux/fs.h> | ||
5 | #include <linux/miscdevice.h> | ||
6 | #include <linux/module.h> | ||
7 | #include <linux/capability.h> | ||
8 | |||
9 | #include <xen/xen.h> | ||
10 | #include <xen/page.h> | ||
11 | #include <xen/xenbus_dev.h> | ||
12 | |||
13 | #include "xenbus_comms.h" | ||
14 | |||
15 | MODULE_LICENSE("GPL"); | ||
16 | |||
17 | static int xenbus_backend_open(struct inode *inode, struct file *filp) | ||
18 | { | ||
19 | if (!capable(CAP_SYS_ADMIN)) | ||
20 | return -EPERM; | ||
21 | |||
22 | return nonseekable_open(inode, filp); | ||
23 | } | ||
24 | |||
25 | static long xenbus_backend_ioctl(struct file *file, unsigned int cmd, unsigned long data) | ||
26 | { | ||
27 | if (!capable(CAP_SYS_ADMIN)) | ||
28 | return -EPERM; | ||
29 | |||
30 | switch (cmd) { | ||
31 | case IOCTL_XENBUS_BACKEND_EVTCHN: | ||
32 | if (xen_store_evtchn > 0) | ||
33 | return xen_store_evtchn; | ||
34 | return -ENODEV; | ||
35 | |||
36 | default: | ||
37 | return -ENOTTY; | ||
38 | } | ||
39 | } | ||
40 | |||
41 | static int xenbus_backend_mmap(struct file *file, struct vm_area_struct *vma) | ||
42 | { | ||
43 | size_t size = vma->vm_end - vma->vm_start; | ||
44 | |||
45 | if (!capable(CAP_SYS_ADMIN)) | ||
46 | return -EPERM; | ||
47 | |||
48 | if ((size > PAGE_SIZE) || (vma->vm_pgoff != 0)) | ||
49 | return -EINVAL; | ||
50 | |||
51 | if (remap_pfn_range(vma, vma->vm_start, | ||
52 | virt_to_pfn(xen_store_interface), | ||
53 | size, vma->vm_page_prot)) | ||
54 | return -EAGAIN; | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | const struct file_operations xenbus_backend_fops = { | ||
60 | .open = xenbus_backend_open, | ||
61 | .mmap = xenbus_backend_mmap, | ||
62 | .unlocked_ioctl = xenbus_backend_ioctl, | ||
63 | }; | ||
64 | |||
65 | static struct miscdevice xenbus_backend_dev = { | ||
66 | .minor = MISC_DYNAMIC_MINOR, | ||
67 | .name = "xen/xenbus_backend", | ||
68 | .fops = &xenbus_backend_fops, | ||
69 | }; | ||
70 | |||
71 | static int __init xenbus_backend_init(void) | ||
72 | { | ||
73 | int err; | ||
74 | |||
75 | if (!xen_initial_domain()) | ||
76 | return -ENODEV; | ||
77 | |||
78 | err = misc_register(&xenbus_backend_dev); | ||
79 | if (err) | ||
80 | printk(KERN_ERR "Could not register xenbus backend device\n"); | ||
81 | return err; | ||
82 | } | ||
83 | |||
84 | static void __exit xenbus_backend_exit(void) | ||
85 | { | ||
86 | misc_deregister(&xenbus_backend_dev); | ||
87 | } | ||
88 | |||
89 | module_init(xenbus_backend_init); | ||
90 | module_exit(xenbus_backend_exit); | ||
diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c new file mode 100644 index 000000000000..527dc2a3b89f --- /dev/null +++ b/drivers/xen/xenbus/xenbus_dev_frontend.c | |||
@@ -0,0 +1,625 @@ | |||
1 | /* | ||
2 | * Driver giving user-space access to the kernel's xenbus connection | ||
3 | * to xenstore. | ||
4 | * | ||
5 | * Copyright (c) 2005, Christian Limpach | ||
6 | * Copyright (c) 2005, Rusty Russell, IBM Corporation | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version 2 | ||
10 | * as published by the Free Software Foundation; or, when distributed | ||
11 | * separately from the Linux kernel or incorporated into other | ||
12 | * software packages, subject to the following license: | ||
13 | * | ||
14 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
15 | * of this source file (the "Software"), to deal in the Software without | ||
16 | * restriction, including without limitation the rights to use, copy, modify, | ||
17 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, | ||
18 | * and to permit persons to whom the Software is furnished to do so, subject to | ||
19 | * the following conditions: | ||
20 | * | ||
21 | * The above copyright notice and this permission notice shall be included in | ||
22 | * all copies or substantial portions of the Software. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
25 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
26 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
27 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
28 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
29 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
30 | * IN THE SOFTWARE. | ||
31 | * | ||
32 | * Changes: | ||
33 | * 2008-10-07 Alex Zeffertt Replaced /proc/xen/xenbus with xenfs filesystem | ||
34 | * and /proc/xen compatibility mount point. | ||
35 | * Turned xenfs into a loadable module. | ||
36 | */ | ||
37 | |||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/errno.h> | ||
40 | #include <linux/uio.h> | ||
41 | #include <linux/notifier.h> | ||
42 | #include <linux/wait.h> | ||
43 | #include <linux/fs.h> | ||
44 | #include <linux/poll.h> | ||
45 | #include <linux/mutex.h> | ||
46 | #include <linux/sched.h> | ||
47 | #include <linux/spinlock.h> | ||
48 | #include <linux/mount.h> | ||
49 | #include <linux/pagemap.h> | ||
50 | #include <linux/uaccess.h> | ||
51 | #include <linux/init.h> | ||
52 | #include <linux/namei.h> | ||
53 | #include <linux/string.h> | ||
54 | #include <linux/slab.h> | ||
55 | #include <linux/miscdevice.h> | ||
56 | #include <linux/module.h> | ||
57 | |||
58 | #include "xenbus_comms.h" | ||
59 | |||
60 | #include <xen/xenbus.h> | ||
61 | #include <xen/xen.h> | ||
62 | #include <asm/xen/hypervisor.h> | ||
63 | |||
64 | MODULE_LICENSE("GPL"); | ||
65 | |||
66 | /* | ||
67 | * An element of a list of outstanding transactions, for which we're | ||
68 | * still waiting a reply. | ||
69 | */ | ||
70 | struct xenbus_transaction_holder { | ||
71 | struct list_head list; | ||
72 | struct xenbus_transaction handle; | ||
73 | }; | ||
74 | |||
75 | /* | ||
76 | * A buffer of data on the queue. | ||
77 | */ | ||
78 | struct read_buffer { | ||
79 | struct list_head list; | ||
80 | unsigned int cons; | ||
81 | unsigned int len; | ||
82 | char msg[]; | ||
83 | }; | ||
84 | |||
85 | struct xenbus_file_priv { | ||
86 | /* | ||
87 | * msgbuffer_mutex is held while partial requests are built up | ||
88 | * and complete requests are acted on. It therefore protects | ||
89 | * the "transactions" and "watches" lists, and the partial | ||
90 | * request length and buffer. | ||
91 | * | ||
92 | * reply_mutex protects the reply being built up to return to | ||
93 | * usermode. It nests inside msgbuffer_mutex but may be held | ||
94 | * alone during a watch callback. | ||
95 | */ | ||
96 | struct mutex msgbuffer_mutex; | ||
97 | |||
98 | /* In-progress transactions */ | ||
99 | struct list_head transactions; | ||
100 | |||
101 | /* Active watches. */ | ||
102 | struct list_head watches; | ||
103 | |||
104 | /* Partial request. */ | ||
105 | unsigned int len; | ||
106 | union { | ||
107 | struct xsd_sockmsg msg; | ||
108 | char buffer[XENSTORE_PAYLOAD_MAX]; | ||
109 | } u; | ||
110 | |||
111 | /* Response queue. */ | ||
112 | struct mutex reply_mutex; | ||
113 | struct list_head read_buffers; | ||
114 | wait_queue_head_t read_waitq; | ||
115 | |||
116 | }; | ||
117 | |||
118 | /* Read out any raw xenbus messages queued up. */ | ||
119 | static ssize_t xenbus_file_read(struct file *filp, | ||
120 | char __user *ubuf, | ||
121 | size_t len, loff_t *ppos) | ||
122 | { | ||
123 | struct xenbus_file_priv *u = filp->private_data; | ||
124 | struct read_buffer *rb; | ||
125 | unsigned i; | ||
126 | int ret; | ||
127 | |||
128 | mutex_lock(&u->reply_mutex); | ||
129 | again: | ||
130 | while (list_empty(&u->read_buffers)) { | ||
131 | mutex_unlock(&u->reply_mutex); | ||
132 | if (filp->f_flags & O_NONBLOCK) | ||
133 | return -EAGAIN; | ||
134 | |||
135 | ret = wait_event_interruptible(u->read_waitq, | ||
136 | !list_empty(&u->read_buffers)); | ||
137 | if (ret) | ||
138 | return ret; | ||
139 | mutex_lock(&u->reply_mutex); | ||
140 | } | ||
141 | |||
142 | rb = list_entry(u->read_buffers.next, struct read_buffer, list); | ||
143 | i = 0; | ||
144 | while (i < len) { | ||
145 | unsigned sz = min((unsigned)len - i, rb->len - rb->cons); | ||
146 | |||
147 | ret = copy_to_user(ubuf + i, &rb->msg[rb->cons], sz); | ||
148 | |||
149 | i += sz - ret; | ||
150 | rb->cons += sz - ret; | ||
151 | |||
152 | if (ret != 0) { | ||
153 | if (i == 0) | ||
154 | i = -EFAULT; | ||
155 | goto out; | ||
156 | } | ||
157 | |||
158 | /* Clear out buffer if it has been consumed */ | ||
159 | if (rb->cons == rb->len) { | ||
160 | list_del(&rb->list); | ||
161 | kfree(rb); | ||
162 | if (list_empty(&u->read_buffers)) | ||
163 | break; | ||
164 | rb = list_entry(u->read_buffers.next, | ||
165 | struct read_buffer, list); | ||
166 | } | ||
167 | } | ||
168 | if (i == 0) | ||
169 | goto again; | ||
170 | |||
171 | out: | ||
172 | mutex_unlock(&u->reply_mutex); | ||
173 | return i; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * Add a buffer to the queue. Caller must hold the appropriate lock | ||
178 | * if the queue is not local. (Commonly the caller will build up | ||
179 | * multiple queued buffers on a temporary local list, and then add it | ||
180 | * to the appropriate list under lock once all the buffers have een | ||
181 | * successfully allocated.) | ||
182 | */ | ||
183 | static int queue_reply(struct list_head *queue, const void *data, size_t len) | ||
184 | { | ||
185 | struct read_buffer *rb; | ||
186 | |||
187 | if (len == 0) | ||
188 | return 0; | ||
189 | |||
190 | rb = kmalloc(sizeof(*rb) + len, GFP_KERNEL); | ||
191 | if (rb == NULL) | ||
192 | return -ENOMEM; | ||
193 | |||
194 | rb->cons = 0; | ||
195 | rb->len = len; | ||
196 | |||
197 | memcpy(rb->msg, data, len); | ||
198 | |||
199 | list_add_tail(&rb->list, queue); | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * Free all the read_buffer s on a list. | ||
205 | * Caller must have sole reference to list. | ||
206 | */ | ||
207 | static void queue_cleanup(struct list_head *list) | ||
208 | { | ||
209 | struct read_buffer *rb; | ||
210 | |||
211 | while (!list_empty(list)) { | ||
212 | rb = list_entry(list->next, struct read_buffer, list); | ||
213 | list_del(list->next); | ||
214 | kfree(rb); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | struct watch_adapter { | ||
219 | struct list_head list; | ||
220 | struct xenbus_watch watch; | ||
221 | struct xenbus_file_priv *dev_data; | ||
222 | char *token; | ||
223 | }; | ||
224 | |||
225 | static void free_watch_adapter(struct watch_adapter *watch) | ||
226 | { | ||
227 | kfree(watch->watch.node); | ||
228 | kfree(watch->token); | ||
229 | kfree(watch); | ||
230 | } | ||
231 | |||
232 | static struct watch_adapter *alloc_watch_adapter(const char *path, | ||
233 | const char *token) | ||
234 | { | ||
235 | struct watch_adapter *watch; | ||
236 | |||
237 | watch = kzalloc(sizeof(*watch), GFP_KERNEL); | ||
238 | if (watch == NULL) | ||
239 | goto out_fail; | ||
240 | |||
241 | watch->watch.node = kstrdup(path, GFP_KERNEL); | ||
242 | if (watch->watch.node == NULL) | ||
243 | goto out_free; | ||
244 | |||
245 | watch->token = kstrdup(token, GFP_KERNEL); | ||
246 | if (watch->token == NULL) | ||
247 | goto out_free; | ||
248 | |||
249 | return watch; | ||
250 | |||
251 | out_free: | ||
252 | free_watch_adapter(watch); | ||
253 | |||
254 | out_fail: | ||
255 | return NULL; | ||
256 | } | ||
257 | |||
258 | static void watch_fired(struct xenbus_watch *watch, | ||
259 | const char **vec, | ||
260 | unsigned int len) | ||
261 | { | ||
262 | struct watch_adapter *adap; | ||
263 | struct xsd_sockmsg hdr; | ||
264 | const char *path, *token; | ||
265 | int path_len, tok_len, body_len, data_len = 0; | ||
266 | int ret; | ||
267 | LIST_HEAD(staging_q); | ||
268 | |||
269 | adap = container_of(watch, struct watch_adapter, watch); | ||
270 | |||
271 | path = vec[XS_WATCH_PATH]; | ||
272 | token = adap->token; | ||
273 | |||
274 | path_len = strlen(path) + 1; | ||
275 | tok_len = strlen(token) + 1; | ||
276 | if (len > 2) | ||
277 | data_len = vec[len] - vec[2] + 1; | ||
278 | body_len = path_len + tok_len + data_len; | ||
279 | |||
280 | hdr.type = XS_WATCH_EVENT; | ||
281 | hdr.len = body_len; | ||
282 | |||
283 | mutex_lock(&adap->dev_data->reply_mutex); | ||
284 | |||
285 | ret = queue_reply(&staging_q, &hdr, sizeof(hdr)); | ||
286 | if (!ret) | ||
287 | ret = queue_reply(&staging_q, path, path_len); | ||
288 | if (!ret) | ||
289 | ret = queue_reply(&staging_q, token, tok_len); | ||
290 | if (!ret && len > 2) | ||
291 | ret = queue_reply(&staging_q, vec[2], data_len); | ||
292 | |||
293 | if (!ret) { | ||
294 | /* success: pass reply list onto watcher */ | ||
295 | list_splice_tail(&staging_q, &adap->dev_data->read_buffers); | ||
296 | wake_up(&adap->dev_data->read_waitq); | ||
297 | } else | ||
298 | queue_cleanup(&staging_q); | ||
299 | |||
300 | mutex_unlock(&adap->dev_data->reply_mutex); | ||
301 | } | ||
302 | |||
303 | static int xenbus_write_transaction(unsigned msg_type, | ||
304 | struct xenbus_file_priv *u) | ||
305 | { | ||
306 | int rc; | ||
307 | void *reply; | ||
308 | struct xenbus_transaction_holder *trans = NULL; | ||
309 | LIST_HEAD(staging_q); | ||
310 | |||
311 | if (msg_type == XS_TRANSACTION_START) { | ||
312 | trans = kmalloc(sizeof(*trans), GFP_KERNEL); | ||
313 | if (!trans) { | ||
314 | rc = -ENOMEM; | ||
315 | goto out; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | reply = xenbus_dev_request_and_reply(&u->u.msg); | ||
320 | if (IS_ERR(reply)) { | ||
321 | kfree(trans); | ||
322 | rc = PTR_ERR(reply); | ||
323 | goto out; | ||
324 | } | ||
325 | |||
326 | if (msg_type == XS_TRANSACTION_START) { | ||
327 | trans->handle.id = simple_strtoul(reply, NULL, 0); | ||
328 | |||
329 | list_add(&trans->list, &u->transactions); | ||
330 | } else if (msg_type == XS_TRANSACTION_END) { | ||
331 | list_for_each_entry(trans, &u->transactions, list) | ||
332 | if (trans->handle.id == u->u.msg.tx_id) | ||
333 | break; | ||
334 | BUG_ON(&trans->list == &u->transactions); | ||
335 | list_del(&trans->list); | ||
336 | |||
337 | kfree(trans); | ||
338 | } | ||
339 | |||
340 | mutex_lock(&u->reply_mutex); | ||
341 | rc = queue_reply(&staging_q, &u->u.msg, sizeof(u->u.msg)); | ||
342 | if (!rc) | ||
343 | rc = queue_reply(&staging_q, reply, u->u.msg.len); | ||
344 | if (!rc) { | ||
345 | list_splice_tail(&staging_q, &u->read_buffers); | ||
346 | wake_up(&u->read_waitq); | ||
347 | } else { | ||
348 | queue_cleanup(&staging_q); | ||
349 | } | ||
350 | mutex_unlock(&u->reply_mutex); | ||
351 | |||
352 | kfree(reply); | ||
353 | |||
354 | out: | ||
355 | return rc; | ||
356 | } | ||
357 | |||
358 | static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u) | ||
359 | { | ||
360 | struct watch_adapter *watch, *tmp_watch; | ||
361 | char *path, *token; | ||
362 | int err, rc; | ||
363 | LIST_HEAD(staging_q); | ||
364 | |||
365 | path = u->u.buffer + sizeof(u->u.msg); | ||
366 | token = memchr(path, 0, u->u.msg.len); | ||
367 | if (token == NULL) { | ||
368 | rc = -EILSEQ; | ||
369 | goto out; | ||
370 | } | ||
371 | token++; | ||
372 | |||
373 | if (msg_type == XS_WATCH) { | ||
374 | watch = alloc_watch_adapter(path, token); | ||
375 | if (watch == NULL) { | ||
376 | rc = -ENOMEM; | ||
377 | goto out; | ||
378 | } | ||
379 | |||
380 | watch->watch.callback = watch_fired; | ||
381 | watch->dev_data = u; | ||
382 | |||
383 | err = register_xenbus_watch(&watch->watch); | ||
384 | if (err) { | ||
385 | free_watch_adapter(watch); | ||
386 | rc = err; | ||
387 | goto out; | ||
388 | } | ||
389 | list_add(&watch->list, &u->watches); | ||
390 | } else { | ||
391 | list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) { | ||
392 | if (!strcmp(watch->token, token) && | ||
393 | !strcmp(watch->watch.node, path)) { | ||
394 | unregister_xenbus_watch(&watch->watch); | ||
395 | list_del(&watch->list); | ||
396 | free_watch_adapter(watch); | ||
397 | break; | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | |||
402 | /* Success. Synthesize a reply to say all is OK. */ | ||
403 | { | ||
404 | struct { | ||
405 | struct xsd_sockmsg hdr; | ||
406 | char body[3]; | ||
407 | } __packed reply = { | ||
408 | { | ||
409 | .type = msg_type, | ||
410 | .len = sizeof(reply.body) | ||
411 | }, | ||
412 | "OK" | ||
413 | }; | ||
414 | |||
415 | mutex_lock(&u->reply_mutex); | ||
416 | rc = queue_reply(&u->read_buffers, &reply, sizeof(reply)); | ||
417 | wake_up(&u->read_waitq); | ||
418 | mutex_unlock(&u->reply_mutex); | ||
419 | } | ||
420 | |||
421 | out: | ||
422 | return rc; | ||
423 | } | ||
424 | |||
425 | static ssize_t xenbus_file_write(struct file *filp, | ||
426 | const char __user *ubuf, | ||
427 | size_t len, loff_t *ppos) | ||
428 | { | ||
429 | struct xenbus_file_priv *u = filp->private_data; | ||
430 | uint32_t msg_type; | ||
431 | int rc = len; | ||
432 | int ret; | ||
433 | LIST_HEAD(staging_q); | ||
434 | |||
435 | /* | ||
436 | * We're expecting usermode to be writing properly formed | ||
437 | * xenbus messages. If they write an incomplete message we | ||
438 | * buffer it up. Once it is complete, we act on it. | ||
439 | */ | ||
440 | |||
441 | /* | ||
442 | * Make sure concurrent writers can't stomp all over each | ||
443 | * other's messages and make a mess of our partial message | ||
444 | * buffer. We don't make any attemppt to stop multiple | ||
445 | * writers from making a mess of each other's incomplete | ||
446 | * messages; we're just trying to guarantee our own internal | ||
447 | * consistency and make sure that single writes are handled | ||
448 | * atomically. | ||
449 | */ | ||
450 | mutex_lock(&u->msgbuffer_mutex); | ||
451 | |||
452 | /* Get this out of the way early to avoid confusion */ | ||
453 | if (len == 0) | ||
454 | goto out; | ||
455 | |||
456 | /* Can't write a xenbus message larger we can buffer */ | ||
457 | if ((len + u->len) > sizeof(u->u.buffer)) { | ||
458 | /* On error, dump existing buffer */ | ||
459 | u->len = 0; | ||
460 | rc = -EINVAL; | ||
461 | goto out; | ||
462 | } | ||
463 | |||
464 | ret = copy_from_user(u->u.buffer + u->len, ubuf, len); | ||
465 | |||
466 | if (ret != 0) { | ||
467 | rc = -EFAULT; | ||
468 | goto out; | ||
469 | } | ||
470 | |||
471 | /* Deal with a partial copy. */ | ||
472 | len -= ret; | ||
473 | rc = len; | ||
474 | |||
475 | u->len += len; | ||
476 | |||
477 | /* Return if we haven't got a full message yet */ | ||
478 | if (u->len < sizeof(u->u.msg)) | ||
479 | goto out; /* not even the header yet */ | ||
480 | |||
481 | /* If we're expecting a message that's larger than we can | ||
482 | possibly send, dump what we have and return an error. */ | ||
483 | if ((sizeof(u->u.msg) + u->u.msg.len) > sizeof(u->u.buffer)) { | ||
484 | rc = -E2BIG; | ||
485 | u->len = 0; | ||
486 | goto out; | ||
487 | } | ||
488 | |||
489 | if (u->len < (sizeof(u->u.msg) + u->u.msg.len)) | ||
490 | goto out; /* incomplete data portion */ | ||
491 | |||
492 | /* | ||
493 | * OK, now we have a complete message. Do something with it. | ||
494 | */ | ||
495 | |||
496 | msg_type = u->u.msg.type; | ||
497 | |||
498 | switch (msg_type) { | ||
499 | case XS_WATCH: | ||
500 | case XS_UNWATCH: | ||
501 | /* (Un)Ask for some path to be watched for changes */ | ||
502 | ret = xenbus_write_watch(msg_type, u); | ||
503 | break; | ||
504 | |||
505 | default: | ||
506 | /* Send out a transaction */ | ||
507 | ret = xenbus_write_transaction(msg_type, u); | ||
508 | break; | ||
509 | } | ||
510 | if (ret != 0) | ||
511 | rc = ret; | ||
512 | |||
513 | /* Buffered message consumed */ | ||
514 | u->len = 0; | ||
515 | |||
516 | out: | ||
517 | mutex_unlock(&u->msgbuffer_mutex); | ||
518 | return rc; | ||
519 | } | ||
520 | |||
521 | static int xenbus_file_open(struct inode *inode, struct file *filp) | ||
522 | { | ||
523 | struct xenbus_file_priv *u; | ||
524 | |||
525 | if (xen_store_evtchn == 0) | ||
526 | return -ENOENT; | ||
527 | |||
528 | nonseekable_open(inode, filp); | ||
529 | |||
530 | u = kzalloc(sizeof(*u), GFP_KERNEL); | ||
531 | if (u == NULL) | ||
532 | return -ENOMEM; | ||
533 | |||
534 | INIT_LIST_HEAD(&u->transactions); | ||
535 | INIT_LIST_HEAD(&u->watches); | ||
536 | INIT_LIST_HEAD(&u->read_buffers); | ||
537 | init_waitqueue_head(&u->read_waitq); | ||
538 | |||
539 | mutex_init(&u->reply_mutex); | ||
540 | mutex_init(&u->msgbuffer_mutex); | ||
541 | |||
542 | filp->private_data = u; | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static int xenbus_file_release(struct inode *inode, struct file *filp) | ||
548 | { | ||
549 | struct xenbus_file_priv *u = filp->private_data; | ||
550 | struct xenbus_transaction_holder *trans, *tmp; | ||
551 | struct watch_adapter *watch, *tmp_watch; | ||
552 | struct read_buffer *rb, *tmp_rb; | ||
553 | |||
554 | /* | ||
555 | * No need for locking here because there are no other users, | ||
556 | * by definition. | ||
557 | */ | ||
558 | |||
559 | list_for_each_entry_safe(trans, tmp, &u->transactions, list) { | ||
560 | xenbus_transaction_end(trans->handle, 1); | ||
561 | list_del(&trans->list); | ||
562 | kfree(trans); | ||
563 | } | ||
564 | |||
565 | list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) { | ||
566 | unregister_xenbus_watch(&watch->watch); | ||
567 | list_del(&watch->list); | ||
568 | free_watch_adapter(watch); | ||
569 | } | ||
570 | |||
571 | list_for_each_entry_safe(rb, tmp_rb, &u->read_buffers, list) { | ||
572 | list_del(&rb->list); | ||
573 | kfree(rb); | ||
574 | } | ||
575 | kfree(u); | ||
576 | |||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | static unsigned int xenbus_file_poll(struct file *file, poll_table *wait) | ||
581 | { | ||
582 | struct xenbus_file_priv *u = file->private_data; | ||
583 | |||
584 | poll_wait(file, &u->read_waitq, wait); | ||
585 | if (!list_empty(&u->read_buffers)) | ||
586 | return POLLIN | POLLRDNORM; | ||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | const struct file_operations xen_xenbus_fops = { | ||
591 | .read = xenbus_file_read, | ||
592 | .write = xenbus_file_write, | ||
593 | .open = xenbus_file_open, | ||
594 | .release = xenbus_file_release, | ||
595 | .poll = xenbus_file_poll, | ||
596 | .llseek = no_llseek, | ||
597 | }; | ||
598 | EXPORT_SYMBOL_GPL(xen_xenbus_fops); | ||
599 | |||
600 | static struct miscdevice xenbus_dev = { | ||
601 | .minor = MISC_DYNAMIC_MINOR, | ||
602 | .name = "xen/xenbus", | ||
603 | .fops = &xen_xenbus_fops, | ||
604 | }; | ||
605 | |||
606 | static int __init xenbus_init(void) | ||
607 | { | ||
608 | int err; | ||
609 | |||
610 | if (!xen_domain()) | ||
611 | return -ENODEV; | ||
612 | |||
613 | err = misc_register(&xenbus_dev); | ||
614 | if (err) | ||
615 | printk(KERN_ERR "Could not register xenbus frontend device\n"); | ||
616 | return err; | ||
617 | } | ||
618 | |||
619 | static void __exit xenbus_exit(void) | ||
620 | { | ||
621 | misc_deregister(&xenbus_dev); | ||
622 | } | ||
623 | |||
624 | module_init(xenbus_init); | ||
625 | module_exit(xenbus_exit); | ||
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 1b178c6e8937..3864967202b5 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c | |||
@@ -291,14 +291,9 @@ void xenbus_dev_shutdown(struct device *_dev) | |||
291 | EXPORT_SYMBOL_GPL(xenbus_dev_shutdown); | 291 | EXPORT_SYMBOL_GPL(xenbus_dev_shutdown); |
292 | 292 | ||
293 | int xenbus_register_driver_common(struct xenbus_driver *drv, | 293 | int xenbus_register_driver_common(struct xenbus_driver *drv, |
294 | struct xen_bus_type *bus, | 294 | struct xen_bus_type *bus) |
295 | struct module *owner, | ||
296 | const char *mod_name) | ||
297 | { | 295 | { |
298 | drv->driver.name = drv->name; | ||
299 | drv->driver.bus = &bus->bus; | 296 | drv->driver.bus = &bus->bus; |
300 | drv->driver.owner = owner; | ||
301 | drv->driver.mod_name = mod_name; | ||
302 | 297 | ||
303 | return driver_register(&drv->driver); | 298 | return driver_register(&drv->driver); |
304 | } | 299 | } |
@@ -730,6 +725,8 @@ static int __init xenbus_init(void) | |||
730 | if (!xen_domain()) | 725 | if (!xen_domain()) |
731 | return -ENODEV; | 726 | return -ENODEV; |
732 | 727 | ||
728 | xenbus_ring_ops_init(); | ||
729 | |||
733 | if (xen_hvm_domain()) { | 730 | if (xen_hvm_domain()) { |
734 | uint64_t v = 0; | 731 | uint64_t v = 0; |
735 | err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); | 732 | err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); |
diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h index 9b1de4e34c64..bb4f92ed8730 100644 --- a/drivers/xen/xenbus/xenbus_probe.h +++ b/drivers/xen/xenbus/xenbus_probe.h | |||
@@ -53,9 +53,7 @@ extern int xenbus_match(struct device *_dev, struct device_driver *_drv); | |||
53 | extern int xenbus_dev_probe(struct device *_dev); | 53 | extern int xenbus_dev_probe(struct device *_dev); |
54 | extern int xenbus_dev_remove(struct device *_dev); | 54 | extern int xenbus_dev_remove(struct device *_dev); |
55 | extern int xenbus_register_driver_common(struct xenbus_driver *drv, | 55 | extern int xenbus_register_driver_common(struct xenbus_driver *drv, |
56 | struct xen_bus_type *bus, | 56 | struct xen_bus_type *bus); |
57 | struct module *owner, | ||
58 | const char *mod_name); | ||
59 | extern int xenbus_probe_node(struct xen_bus_type *bus, | 57 | extern int xenbus_probe_node(struct xen_bus_type *bus, |
60 | const char *type, | 58 | const char *type, |
61 | const char *nodename); | 59 | const char *nodename); |
@@ -76,4 +74,6 @@ extern void xenbus_otherend_changed(struct xenbus_watch *watch, | |||
76 | extern int xenbus_read_otherend_details(struct xenbus_device *xendev, | 74 | extern int xenbus_read_otherend_details(struct xenbus_device *xendev, |
77 | char *id_node, char *path_node); | 75 | char *id_node, char *path_node); |
78 | 76 | ||
77 | void xenbus_ring_ops_init(void); | ||
78 | |||
79 | #endif | 79 | #endif |
diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c index c3c7cd195c11..257be37d9091 100644 --- a/drivers/xen/xenbus/xenbus_probe_backend.c +++ b/drivers/xen/xenbus/xenbus_probe_backend.c | |||
@@ -232,15 +232,13 @@ int xenbus_dev_is_online(struct xenbus_device *dev) | |||
232 | } | 232 | } |
233 | EXPORT_SYMBOL_GPL(xenbus_dev_is_online); | 233 | EXPORT_SYMBOL_GPL(xenbus_dev_is_online); |
234 | 234 | ||
235 | int __xenbus_register_backend(struct xenbus_driver *drv, | 235 | int xenbus_register_backend(struct xenbus_driver *drv) |
236 | struct module *owner, const char *mod_name) | ||
237 | { | 236 | { |
238 | drv->read_otherend_details = read_frontend_details; | 237 | drv->read_otherend_details = read_frontend_details; |
239 | 238 | ||
240 | return xenbus_register_driver_common(drv, &xenbus_backend, | 239 | return xenbus_register_driver_common(drv, &xenbus_backend); |
241 | owner, mod_name); | ||
242 | } | 240 | } |
243 | EXPORT_SYMBOL_GPL(__xenbus_register_backend); | 241 | EXPORT_SYMBOL_GPL(xenbus_register_backend); |
244 | 242 | ||
245 | static int backend_probe_and_watch(struct notifier_block *notifier, | 243 | static int backend_probe_and_watch(struct notifier_block *notifier, |
246 | unsigned long event, | 244 | unsigned long event, |
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index 2f73195512b4..9c57819df51a 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c | |||
@@ -230,15 +230,13 @@ static void wait_for_devices(struct xenbus_driver *xendrv) | |||
230 | print_device_status); | 230 | print_device_status); |
231 | } | 231 | } |
232 | 232 | ||
233 | int __xenbus_register_frontend(struct xenbus_driver *drv, | 233 | int xenbus_register_frontend(struct xenbus_driver *drv) |
234 | struct module *owner, const char *mod_name) | ||
235 | { | 234 | { |
236 | int ret; | 235 | int ret; |
237 | 236 | ||
238 | drv->read_otherend_details = read_backend_details; | 237 | drv->read_otherend_details = read_backend_details; |
239 | 238 | ||
240 | ret = xenbus_register_driver_common(drv, &xenbus_frontend, | 239 | ret = xenbus_register_driver_common(drv, &xenbus_frontend); |
241 | owner, mod_name); | ||
242 | if (ret) | 240 | if (ret) |
243 | return ret; | 241 | return ret; |
244 | 242 | ||
@@ -247,7 +245,7 @@ int __xenbus_register_frontend(struct xenbus_driver *drv, | |||
247 | 245 | ||
248 | return 0; | 246 | return 0; |
249 | } | 247 | } |
250 | EXPORT_SYMBOL_GPL(__xenbus_register_frontend); | 248 | EXPORT_SYMBOL_GPL(xenbus_register_frontend); |
251 | 249 | ||
252 | static DECLARE_WAIT_QUEUE_HEAD(backend_state_wq); | 250 | static DECLARE_WAIT_QUEUE_HEAD(backend_state_wq); |
253 | static int backend_state; | 251 | static int backend_state; |
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index ede860f921df..d1c217b23a42 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c | |||
@@ -532,21 +532,18 @@ int xenbus_printf(struct xenbus_transaction t, | |||
532 | { | 532 | { |
533 | va_list ap; | 533 | va_list ap; |
534 | int ret; | 534 | int ret; |
535 | #define PRINTF_BUFFER_SIZE 4096 | 535 | char *buf; |
536 | char *printf_buffer; | ||
537 | |||
538 | printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_NOIO | __GFP_HIGH); | ||
539 | if (printf_buffer == NULL) | ||
540 | return -ENOMEM; | ||
541 | 536 | ||
542 | va_start(ap, fmt); | 537 | va_start(ap, fmt); |
543 | ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap); | 538 | buf = kvasprintf(GFP_NOIO | __GFP_HIGH, fmt, ap); |
544 | va_end(ap); | 539 | va_end(ap); |
545 | 540 | ||
546 | BUG_ON(ret > PRINTF_BUFFER_SIZE-1); | 541 | if (!buf) |
547 | ret = xenbus_write(t, dir, node, printf_buffer); | 542 | return -ENOMEM; |
543 | |||
544 | ret = xenbus_write(t, dir, node, buf); | ||
548 | 545 | ||
549 | kfree(printf_buffer); | 546 | kfree(buf); |
550 | 547 | ||
551 | return ret; | 548 | return ret; |
552 | } | 549 | } |
@@ -801,6 +798,12 @@ static int process_msg(void) | |||
801 | goto out; | 798 | goto out; |
802 | } | 799 | } |
803 | 800 | ||
801 | if (msg->hdr.len > XENSTORE_PAYLOAD_MAX) { | ||
802 | kfree(msg); | ||
803 | err = -EINVAL; | ||
804 | goto out; | ||
805 | } | ||
806 | |||
804 | body = kmalloc(msg->hdr.len + 1, GFP_NOIO | __GFP_HIGH); | 807 | body = kmalloc(msg->hdr.len + 1, GFP_NOIO | __GFP_HIGH); |
805 | if (body == NULL) { | 808 | if (body == NULL) { |
806 | kfree(msg); | 809 | kfree(msg); |