Commit a4ec046c98283d9f36817589081e14850570739f
Exists in
master
and in
7 other branches
Merge branch 'upstream/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen
* 'upstream/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen: (23 commits) xen/events: Use PIRQ instead of GSI value when unmapping MSI/MSI-X irqs. xen: set IO permission early (before early_cpu_init()) xen: re-enable boot-time ballooning xen/balloon: make sure we only include remaining extra ram xen/balloon: the balloon_lock is useless xen: add extra pages to balloon xen: make evtchn's name less generic xen/evtchn: the evtchn device is non-seekable Revert "xen/privcmd: create address space to allow writable mmaps" xen/events: use locked set|clear_bit() for cpu_evtchn_mask xen/evtchn: clear secondary CPUs' cpu_evtchn_mask[] after restore xen/xenfs: update xenfs_mount for new prototype xen: fix header export to userspace xen: implement XENMEM_machphys_mapping xen: set vma flag VM_PFNMAP in the privcmd mmap file_op xen: xenfs: privcmd: check put_user() return code xen/evtchn: add missing static xen/evtchn: Fix name of Xen event-channel device xen/evtchn: don't do unbind_from_irqhandler under spinlock xen/evtchn: remove spurious barrier ...
Showing 16 changed files Side-by-side Diff
- arch/x86/include/asm/xen/interface.h
- arch/x86/include/asm/xen/interface_32.h
- arch/x86/include/asm/xen/interface_64.h
- arch/x86/include/asm/xen/page.h
- arch/x86/xen/enlighten.c
- arch/x86/xen/mmu.c
- arch/x86/xen/setup.c
- drivers/xen/Makefile
- drivers/xen/balloon.c
- drivers/xen/events.c
- drivers/xen/evtchn.c
- drivers/xen/xenfs/privcmd.c
- drivers/xen/xenfs/super.c
- include/xen/interface/memory.h
- include/xen/page.h
- include/xen/privcmd.h
arch/x86/include/asm/xen/interface.h
... | ... | @@ -61,9 +61,9 @@ |
61 | 61 | #define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) |
62 | 62 | #endif |
63 | 63 | |
64 | -#ifndef machine_to_phys_mapping | |
65 | -#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) | |
66 | -#endif | |
64 | +#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START) | |
65 | +#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END) | |
66 | +#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>__MACH2PHYS_SHIFT) | |
67 | 67 | |
68 | 68 | /* Maximum number of virtual CPUs in multi-processor guests. */ |
69 | 69 | #define MAX_VIRT_CPUS 32 |
arch/x86/include/asm/xen/interface_32.h
... | ... | @@ -32,6 +32,11 @@ |
32 | 32 | /* And the trap vector is... */ |
33 | 33 | #define TRAP_INSTR "int $0x82" |
34 | 34 | |
35 | +#define __MACH2PHYS_VIRT_START 0xF5800000 | |
36 | +#define __MACH2PHYS_VIRT_END 0xF6800000 | |
37 | + | |
38 | +#define __MACH2PHYS_SHIFT 2 | |
39 | + | |
35 | 40 | /* |
36 | 41 | * Virtual addresses beyond this are not modifiable by guest OSes. The |
37 | 42 | * machine->physical mapping table starts at this address, read-only. |
arch/x86/include/asm/xen/interface_64.h
... | ... | @@ -39,18 +39,7 @@ |
39 | 39 | #define __HYPERVISOR_VIRT_END 0xFFFF880000000000 |
40 | 40 | #define __MACH2PHYS_VIRT_START 0xFFFF800000000000 |
41 | 41 | #define __MACH2PHYS_VIRT_END 0xFFFF804000000000 |
42 | - | |
43 | -#ifndef HYPERVISOR_VIRT_START | |
44 | -#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) | |
45 | -#define HYPERVISOR_VIRT_END mk_unsigned_long(__HYPERVISOR_VIRT_END) | |
46 | -#endif | |
47 | - | |
48 | -#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START) | |
49 | -#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END) | |
50 | -#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3) | |
51 | -#ifndef machine_to_phys_mapping | |
52 | -#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) | |
53 | -#endif | |
42 | +#define __MACH2PHYS_SHIFT 3 | |
54 | 43 | |
55 | 44 | /* |
56 | 45 | * int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base) |
arch/x86/include/asm/xen/page.h
... | ... | @@ -5,6 +5,7 @@ |
5 | 5 | #include <linux/types.h> |
6 | 6 | #include <linux/spinlock.h> |
7 | 7 | #include <linux/pfn.h> |
8 | +#include <linux/mm.h> | |
8 | 9 | |
9 | 10 | #include <asm/uaccess.h> |
10 | 11 | #include <asm/page.h> |
... | ... | @@ -35,6 +36,8 @@ |
35 | 36 | #define MAX_DOMAIN_PAGES \ |
36 | 37 | ((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE)) |
37 | 38 | |
39 | +extern unsigned long *machine_to_phys_mapping; | |
40 | +extern unsigned int machine_to_phys_order; | |
38 | 41 | |
39 | 42 | extern unsigned long get_phys_to_machine(unsigned long pfn); |
40 | 43 | extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn); |
41 | 44 | |
... | ... | @@ -69,10 +72,8 @@ |
69 | 72 | if (xen_feature(XENFEAT_auto_translated_physmap)) |
70 | 73 | return mfn; |
71 | 74 | |
72 | -#if 0 | |
73 | 75 | if (unlikely((mfn >> machine_to_phys_order) != 0)) |
74 | - return max_mapnr; | |
75 | -#endif | |
76 | + return ~0; | |
76 | 77 | |
77 | 78 | pfn = 0; |
78 | 79 | /* |
arch/x86/xen/enlighten.c
... | ... | @@ -75,6 +75,11 @@ |
75 | 75 | enum xen_domain_type xen_domain_type = XEN_NATIVE; |
76 | 76 | EXPORT_SYMBOL_GPL(xen_domain_type); |
77 | 77 | |
78 | +unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START; | |
79 | +EXPORT_SYMBOL(machine_to_phys_mapping); | |
80 | +unsigned int machine_to_phys_order; | |
81 | +EXPORT_SYMBOL(machine_to_phys_order); | |
82 | + | |
78 | 83 | struct start_info *xen_start_info; |
79 | 84 | EXPORT_SYMBOL_GPL(xen_start_info); |
80 | 85 | |
... | ... | @@ -1090,6 +1095,8 @@ |
1090 | 1095 | /* First C function to be called on Xen boot */ |
1091 | 1096 | asmlinkage void __init xen_start_kernel(void) |
1092 | 1097 | { |
1098 | + struct physdev_set_iopl set_iopl; | |
1099 | + int rc; | |
1093 | 1100 | pgd_t *pgd; |
1094 | 1101 | |
1095 | 1102 | if (!xen_start_info) |
... | ... | @@ -1097,6 +1104,8 @@ |
1097 | 1104 | |
1098 | 1105 | xen_domain_type = XEN_PV_DOMAIN; |
1099 | 1106 | |
1107 | + xen_setup_machphys_mapping(); | |
1108 | + | |
1100 | 1109 | /* Install Xen paravirt ops */ |
1101 | 1110 | pv_info = xen_info; |
1102 | 1111 | pv_init_ops = xen_init_ops; |
1103 | 1112 | |
... | ... | @@ -1202,9 +1211,17 @@ |
1202 | 1211 | #else |
1203 | 1212 | pv_info.kernel_rpl = 0; |
1204 | 1213 | #endif |
1205 | - | |
1206 | 1214 | /* set the limit of our address space */ |
1207 | 1215 | xen_reserve_top(); |
1216 | + | |
1217 | + /* We used to do this in xen_arch_setup, but that is too late on AMD | |
1218 | + * were early_cpu_init (run before ->arch_setup()) calls early_amd_init | |
1219 | + * which pokes 0xcf8 port. | |
1220 | + */ | |
1221 | + set_iopl.iopl = 1; | |
1222 | + rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); | |
1223 | + if (rc != 0) | |
1224 | + xen_raw_printk("physdev_op failed %d\n", rc); | |
1208 | 1225 | |
1209 | 1226 | #ifdef CONFIG_X86_32 |
1210 | 1227 | /* set up basic CPUID stuff */ |
arch/x86/xen/mmu.c
... | ... | @@ -2034,6 +2034,20 @@ |
2034 | 2034 | set_page_prot(pmd, PAGE_KERNEL_RO); |
2035 | 2035 | } |
2036 | 2036 | |
2037 | +void __init xen_setup_machphys_mapping(void) | |
2038 | +{ | |
2039 | + struct xen_machphys_mapping mapping; | |
2040 | + unsigned long machine_to_phys_nr_ents; | |
2041 | + | |
2042 | + if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) { | |
2043 | + machine_to_phys_mapping = (unsigned long *)mapping.v_start; | |
2044 | + machine_to_phys_nr_ents = mapping.max_mfn + 1; | |
2045 | + } else { | |
2046 | + machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES; | |
2047 | + } | |
2048 | + machine_to_phys_order = fls(machine_to_phys_nr_ents - 1); | |
2049 | +} | |
2050 | + | |
2037 | 2051 | #ifdef CONFIG_X86_64 |
2038 | 2052 | static void convert_pfn_mfn(void *v) |
2039 | 2053 | { |
... | ... | @@ -2627,7 +2641,8 @@ |
2627 | 2641 | |
2628 | 2642 | prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP); |
2629 | 2643 | |
2630 | - vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP; | |
2644 | + BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_RESERVED | VM_IO)) == | |
2645 | + (VM_PFNMAP | VM_RESERVED | VM_IO))); | |
2631 | 2646 | |
2632 | 2647 | rmd.mfn = mfn; |
2633 | 2648 | rmd.prot = prot; |
arch/x86/xen/setup.c
... | ... | @@ -248,8 +248,7 @@ |
248 | 248 | else |
249 | 249 | extra_pages = 0; |
250 | 250 | |
251 | - if (!xen_initial_domain()) | |
252 | - xen_add_extra_mem(extra_pages); | |
251 | + xen_add_extra_mem(extra_pages); | |
253 | 252 | |
254 | 253 | return "Xen"; |
255 | 254 | } |
... | ... | @@ -337,9 +336,6 @@ |
337 | 336 | |
338 | 337 | void __init xen_arch_setup(void) |
339 | 338 | { |
340 | - struct physdev_set_iopl set_iopl; | |
341 | - int rc; | |
342 | - | |
343 | 339 | xen_panic_handler_init(); |
344 | 340 | |
345 | 341 | HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments); |
... | ... | @@ -355,11 +351,6 @@ |
355 | 351 | |
356 | 352 | xen_enable_sysenter(); |
357 | 353 | xen_enable_syscall(); |
358 | - | |
359 | - set_iopl.iopl = 1; | |
360 | - rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); | |
361 | - if (rc != 0) | |
362 | - printk(KERN_INFO "physdev_op failed %d\n", rc); | |
363 | 354 | |
364 | 355 | #ifdef CONFIG_ACPI |
365 | 356 | if (!(xen_start_info->flags & SIF_INITDOMAIN)) { |
drivers/xen/Makefile
... | ... | @@ -8,10 +8,12 @@ |
8 | 8 | obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o |
9 | 9 | obj-$(CONFIG_XEN_XENCOMM) += xencomm.o |
10 | 10 | obj-$(CONFIG_XEN_BALLOON) += balloon.o |
11 | -obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o | |
11 | +obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o | |
12 | 12 | obj-$(CONFIG_XENFS) += xenfs/ |
13 | 13 | obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o |
14 | 14 | obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o |
15 | 15 | obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o |
16 | 16 | obj-$(CONFIG_XEN_DOM0) += pci.o |
17 | + | |
18 | +xen-evtchn-y := evtchn.o |
drivers/xen/balloon.c
... | ... | @@ -50,6 +50,7 @@ |
50 | 50 | #include <asm/pgtable.h> |
51 | 51 | #include <asm/uaccess.h> |
52 | 52 | #include <asm/tlb.h> |
53 | +#include <asm/e820.h> | |
53 | 54 | |
54 | 55 | #include <asm/xen/hypervisor.h> |
55 | 56 | #include <asm/xen/hypercall.h> |
... | ... | @@ -119,7 +120,7 @@ |
119 | 120 | } |
120 | 121 | |
121 | 122 | /* balloon_append: add the given page to the balloon. */ |
122 | -static void balloon_append(struct page *page) | |
123 | +static void __balloon_append(struct page *page) | |
123 | 124 | { |
124 | 125 | /* Lowmem is re-populated first, so highmem pages go at list tail. */ |
125 | 126 | if (PageHighMem(page)) { |
126 | 127 | |
... | ... | @@ -130,7 +131,11 @@ |
130 | 131 | list_add(&page->lru, &ballooned_pages); |
131 | 132 | balloon_stats.balloon_low++; |
132 | 133 | } |
134 | +} | |
133 | 135 | |
136 | +static void balloon_append(struct page *page) | |
137 | +{ | |
138 | + __balloon_append(page); | |
134 | 139 | totalram_pages--; |
135 | 140 | } |
136 | 141 | |
... | ... | @@ -191,7 +196,7 @@ |
191 | 196 | |
192 | 197 | static int increase_reservation(unsigned long nr_pages) |
193 | 198 | { |
194 | - unsigned long pfn, i, flags; | |
199 | + unsigned long pfn, i; | |
195 | 200 | struct page *page; |
196 | 201 | long rc; |
197 | 202 | struct xen_memory_reservation reservation = { |
... | ... | @@ -203,8 +208,6 @@ |
203 | 208 | if (nr_pages > ARRAY_SIZE(frame_list)) |
204 | 209 | nr_pages = ARRAY_SIZE(frame_list); |
205 | 210 | |
206 | - spin_lock_irqsave(&xen_reservation_lock, flags); | |
207 | - | |
208 | 211 | page = balloon_first_page(); |
209 | 212 | for (i = 0; i < nr_pages; i++) { |
210 | 213 | BUG_ON(page == NULL); |
211 | 214 | |
... | ... | @@ -247,14 +250,12 @@ |
247 | 250 | balloon_stats.current_pages += rc; |
248 | 251 | |
249 | 252 | out: |
250 | - spin_unlock_irqrestore(&xen_reservation_lock, flags); | |
251 | - | |
252 | 253 | return rc < 0 ? rc : rc != nr_pages; |
253 | 254 | } |
254 | 255 | |
255 | 256 | static int decrease_reservation(unsigned long nr_pages) |
256 | 257 | { |
257 | - unsigned long pfn, i, flags; | |
258 | + unsigned long pfn, i; | |
258 | 259 | struct page *page; |
259 | 260 | int need_sleep = 0; |
260 | 261 | int ret; |
... | ... | @@ -292,8 +293,6 @@ |
292 | 293 | kmap_flush_unused(); |
293 | 294 | flush_tlb_all(); |
294 | 295 | |
295 | - spin_lock_irqsave(&xen_reservation_lock, flags); | |
296 | - | |
297 | 296 | /* No more mappings: invalidate P2M and add to balloon. */ |
298 | 297 | for (i = 0; i < nr_pages; i++) { |
299 | 298 | pfn = mfn_to_pfn(frame_list[i]); |
... | ... | @@ -308,8 +307,6 @@ |
308 | 307 | |
309 | 308 | balloon_stats.current_pages -= nr_pages; |
310 | 309 | |
311 | - spin_unlock_irqrestore(&xen_reservation_lock, flags); | |
312 | - | |
313 | 310 | return need_sleep; |
314 | 311 | } |
315 | 312 | |
... | ... | @@ -395,7 +392,7 @@ |
395 | 392 | |
396 | 393 | static int __init balloon_init(void) |
397 | 394 | { |
398 | - unsigned long pfn; | |
395 | + unsigned long pfn, extra_pfn_end; | |
399 | 396 | struct page *page; |
400 | 397 | |
401 | 398 | if (!xen_pv_domain()) |
402 | 399 | |
... | ... | @@ -416,10 +413,15 @@ |
416 | 413 | register_balloon(&balloon_sysdev); |
417 | 414 | |
418 | 415 | /* Initialise the balloon with excess memory space. */ |
419 | - for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) { | |
416 | + extra_pfn_end = min(e820_end_of_ram_pfn(), | |
417 | + (unsigned long)PFN_DOWN(xen_extra_mem_start + xen_extra_mem_size)); | |
418 | + for (pfn = PFN_UP(xen_extra_mem_start); | |
419 | + pfn < extra_pfn_end; | |
420 | + pfn++) { | |
420 | 421 | page = pfn_to_page(pfn); |
421 | - if (!PageReserved(page)) | |
422 | - balloon_append(page); | |
422 | + /* totalram_pages doesn't include the boot-time | |
423 | + balloon extension, so don't subtract from it. */ | |
424 | + __balloon_append(page); | |
423 | 425 | } |
424 | 426 | |
425 | 427 | target_watch.callback = watch_target; |
drivers/xen/events.c
... | ... | @@ -278,17 +278,17 @@ |
278 | 278 | cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu)); |
279 | 279 | #endif |
280 | 280 | |
281 | - __clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq))); | |
282 | - __set_bit(chn, cpu_evtchn_mask(cpu)); | |
281 | + clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq))); | |
282 | + set_bit(chn, cpu_evtchn_mask(cpu)); | |
283 | 283 | |
284 | 284 | irq_info[irq].cpu = cpu; |
285 | 285 | } |
286 | 286 | |
287 | 287 | static void init_evtchn_cpu_bindings(void) |
288 | 288 | { |
289 | + int i; | |
289 | 290 | #ifdef CONFIG_SMP |
290 | 291 | struct irq_desc *desc; |
291 | - int i; | |
292 | 292 | |
293 | 293 | /* By default all event channels notify CPU#0. */ |
294 | 294 | for_each_irq_desc(i, desc) { |
... | ... | @@ -296,7 +296,10 @@ |
296 | 296 | } |
297 | 297 | #endif |
298 | 298 | |
299 | - memset(cpu_evtchn_mask(0), ~0, sizeof(struct cpu_evtchn_s)); | |
299 | + for_each_possible_cpu(i) | |
300 | + memset(cpu_evtchn_mask(i), | |
301 | + (i == 0) ? ~0 : 0, sizeof(struct cpu_evtchn_s)); | |
302 | + | |
300 | 303 | } |
301 | 304 | |
302 | 305 | static inline void clear_evtchn(int port) |
... | ... | @@ -752,7 +755,7 @@ |
752 | 755 | goto out; |
753 | 756 | |
754 | 757 | if (xen_initial_domain()) { |
755 | - unmap_irq.pirq = info->u.pirq.gsi; | |
758 | + unmap_irq.pirq = info->u.pirq.pirq; | |
756 | 759 | unmap_irq.domid = DOMID_SELF; |
757 | 760 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); |
758 | 761 | if (rc) { |
drivers/xen/evtchn.c
... | ... | @@ -69,20 +69,51 @@ |
69 | 69 | const char *name; |
70 | 70 | }; |
71 | 71 | |
72 | -/* Who's bound to each port? */ | |
73 | -static struct per_user_data *port_user[NR_EVENT_CHANNELS]; | |
72 | +/* | |
73 | + * Who's bound to each port? This is logically an array of struct | |
74 | + * per_user_data *, but we encode the current enabled-state in bit 0. | |
75 | + */ | |
76 | +static unsigned long *port_user; | |
74 | 77 | static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */ |
75 | 78 | |
76 | -irqreturn_t evtchn_interrupt(int irq, void *data) | |
79 | +static inline struct per_user_data *get_port_user(unsigned port) | |
77 | 80 | { |
81 | + return (struct per_user_data *)(port_user[port] & ~1); | |
82 | +} | |
83 | + | |
84 | +static inline void set_port_user(unsigned port, struct per_user_data *u) | |
85 | +{ | |
86 | + port_user[port] = (unsigned long)u; | |
87 | +} | |
88 | + | |
89 | +static inline bool get_port_enabled(unsigned port) | |
90 | +{ | |
91 | + return port_user[port] & 1; | |
92 | +} | |
93 | + | |
94 | +static inline void set_port_enabled(unsigned port, bool enabled) | |
95 | +{ | |
96 | + if (enabled) | |
97 | + port_user[port] |= 1; | |
98 | + else | |
99 | + port_user[port] &= ~1; | |
100 | +} | |
101 | + | |
102 | +static irqreturn_t evtchn_interrupt(int irq, void *data) | |
103 | +{ | |
78 | 104 | unsigned int port = (unsigned long)data; |
79 | 105 | struct per_user_data *u; |
80 | 106 | |
81 | 107 | spin_lock(&port_user_lock); |
82 | 108 | |
83 | - u = port_user[port]; | |
109 | + u = get_port_user(port); | |
84 | 110 | |
111 | + WARN(!get_port_enabled(port), | |
112 | + "Interrupt for port %d, but apparently not enabled; per-user %p\n", | |
113 | + port, u); | |
114 | + | |
85 | 115 | disable_irq_nosync(irq); |
116 | + set_port_enabled(port, false); | |
86 | 117 | |
87 | 118 | if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { |
88 | 119 | u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port; |
89 | 120 | |
... | ... | @@ -92,9 +123,8 @@ |
92 | 123 | kill_fasync(&u->evtchn_async_queue, |
93 | 124 | SIGIO, POLL_IN); |
94 | 125 | } |
95 | - } else { | |
126 | + } else | |
96 | 127 | u->ring_overflow = 1; |
97 | - } | |
98 | 128 | |
99 | 129 | spin_unlock(&port_user_lock); |
100 | 130 | |
... | ... | @@ -198,9 +228,18 @@ |
198 | 228 | goto out; |
199 | 229 | |
200 | 230 | spin_lock_irq(&port_user_lock); |
201 | - for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) | |
202 | - if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u)) | |
203 | - enable_irq(irq_from_evtchn(kbuf[i])); | |
231 | + | |
232 | + for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) { | |
233 | + unsigned port = kbuf[i]; | |
234 | + | |
235 | + if (port < NR_EVENT_CHANNELS && | |
236 | + get_port_user(port) == u && | |
237 | + !get_port_enabled(port)) { | |
238 | + set_port_enabled(port, true); | |
239 | + enable_irq(irq_from_evtchn(port)); | |
240 | + } | |
241 | + } | |
242 | + | |
204 | 243 | spin_unlock_irq(&port_user_lock); |
205 | 244 | |
206 | 245 | rc = count; |
... | ... | @@ -222,8 +261,9 @@ |
222 | 261 | * interrupt handler yet, and our caller has already |
223 | 262 | * serialized bind operations.) |
224 | 263 | */ |
225 | - BUG_ON(port_user[port] != NULL); | |
226 | - port_user[port] = u; | |
264 | + BUG_ON(get_port_user(port) != NULL); | |
265 | + set_port_user(port, u); | |
266 | + set_port_enabled(port, true); /* start enabled */ | |
227 | 267 | |
228 | 268 | rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, |
229 | 269 | u->name, (void *)(unsigned long)port); |
... | ... | @@ -239,10 +279,7 @@ |
239 | 279 | |
240 | 280 | unbind_from_irqhandler(irq, (void *)(unsigned long)port); |
241 | 281 | |
242 | - /* make sure we unbind the irq handler before clearing the port */ | |
243 | - barrier(); | |
244 | - | |
245 | - port_user[port] = NULL; | |
282 | + set_port_user(port, NULL); | |
246 | 283 | } |
247 | 284 | |
248 | 285 | static long evtchn_ioctl(struct file *file, |
249 | 286 | |
250 | 287 | |
... | ... | @@ -333,15 +370,17 @@ |
333 | 370 | spin_lock_irq(&port_user_lock); |
334 | 371 | |
335 | 372 | rc = -ENOTCONN; |
336 | - if (port_user[unbind.port] != u) { | |
373 | + if (get_port_user(unbind.port) != u) { | |
337 | 374 | spin_unlock_irq(&port_user_lock); |
338 | 375 | break; |
339 | 376 | } |
340 | 377 | |
341 | - evtchn_unbind_from_user(u, unbind.port); | |
378 | + disable_irq(irq_from_evtchn(unbind.port)); | |
342 | 379 | |
343 | 380 | spin_unlock_irq(&port_user_lock); |
344 | 381 | |
382 | + evtchn_unbind_from_user(u, unbind.port); | |
383 | + | |
345 | 384 | rc = 0; |
346 | 385 | break; |
347 | 386 | } |
... | ... | @@ -355,7 +394,7 @@ |
355 | 394 | |
356 | 395 | if (notify.port >= NR_EVENT_CHANNELS) { |
357 | 396 | rc = -EINVAL; |
358 | - } else if (port_user[notify.port] != u) { | |
397 | + } else if (get_port_user(notify.port) != u) { | |
359 | 398 | rc = -ENOTCONN; |
360 | 399 | } else { |
361 | 400 | notify_remote_via_evtchn(notify.port); |
... | ... | @@ -431,7 +470,7 @@ |
431 | 470 | |
432 | 471 | filp->private_data = u; |
433 | 472 | |
434 | - return 0; | |
473 | + return nonseekable_open(inode, filp);; | |
435 | 474 | } |
436 | 475 | |
437 | 476 | static int evtchn_release(struct inode *inode, struct file *filp) |
438 | 477 | |
439 | 478 | |
... | ... | @@ -444,14 +483,21 @@ |
444 | 483 | free_page((unsigned long)u->ring); |
445 | 484 | |
446 | 485 | for (i = 0; i < NR_EVENT_CHANNELS; i++) { |
447 | - if (port_user[i] != u) | |
486 | + if (get_port_user(i) != u) | |
448 | 487 | continue; |
449 | 488 | |
450 | - evtchn_unbind_from_user(port_user[i], i); | |
489 | + disable_irq(irq_from_evtchn(i)); | |
451 | 490 | } |
452 | 491 | |
453 | 492 | spin_unlock_irq(&port_user_lock); |
454 | 493 | |
494 | + for (i = 0; i < NR_EVENT_CHANNELS; i++) { | |
495 | + if (get_port_user(i) != u) | |
496 | + continue; | |
497 | + | |
498 | + evtchn_unbind_from_user(get_port_user(i), i); | |
499 | + } | |
500 | + | |
455 | 501 | kfree(u->name); |
456 | 502 | kfree(u); |
457 | 503 | |
458 | 504 | |
... | ... | @@ -467,12 +513,12 @@ |
467 | 513 | .fasync = evtchn_fasync, |
468 | 514 | .open = evtchn_open, |
469 | 515 | .release = evtchn_release, |
470 | - .llseek = noop_llseek, | |
516 | + .llseek = no_llseek, | |
471 | 517 | }; |
472 | 518 | |
473 | 519 | static struct miscdevice evtchn_miscdev = { |
474 | 520 | .minor = MISC_DYNAMIC_MINOR, |
475 | - .name = "evtchn", | |
521 | + .name = "xen/evtchn", | |
476 | 522 | .fops = &evtchn_fops, |
477 | 523 | }; |
478 | 524 | static int __init evtchn_init(void) |
479 | 525 | |
... | ... | @@ -482,8 +528,11 @@ |
482 | 528 | if (!xen_domain()) |
483 | 529 | return -ENODEV; |
484 | 530 | |
531 | + port_user = kcalloc(NR_EVENT_CHANNELS, sizeof(*port_user), GFP_KERNEL); | |
532 | + if (port_user == NULL) | |
533 | + return -ENOMEM; | |
534 | + | |
485 | 535 | spin_lock_init(&port_user_lock); |
486 | - memset(port_user, 0, sizeof(port_user)); | |
487 | 536 | |
488 | 537 | /* Create '/dev/misc/evtchn'. */ |
489 | 538 | err = misc_register(&evtchn_miscdev); |
... | ... | @@ -499,6 +548,9 @@ |
499 | 548 | |
500 | 549 | static void __exit evtchn_cleanup(void) |
501 | 550 | { |
551 | + kfree(port_user); | |
552 | + port_user = NULL; | |
553 | + | |
502 | 554 | misc_deregister(&evtchn_miscdev); |
503 | 555 | } |
504 | 556 |
drivers/xen/xenfs/privcmd.c
... | ... | @@ -265,9 +265,7 @@ |
265 | 265 | xen_pfn_t *mfnp = data; |
266 | 266 | struct mmap_batch_state *st = state; |
267 | 267 | |
268 | - put_user(*mfnp, st->user++); | |
269 | - | |
270 | - return 0; | |
268 | + return put_user(*mfnp, st->user++); | |
271 | 269 | } |
272 | 270 | |
273 | 271 | static struct vm_operations_struct privcmd_vm_ops; |
274 | 272 | |
... | ... | @@ -322,10 +320,8 @@ |
322 | 320 | up_write(&mm->mmap_sem); |
323 | 321 | |
324 | 322 | if (state.err > 0) { |
325 | - ret = 0; | |
326 | - | |
327 | 323 | state.user = m.arr; |
328 | - traverse_pages(m.num, sizeof(xen_pfn_t), | |
324 | + ret = traverse_pages(m.num, sizeof(xen_pfn_t), | |
329 | 325 | &pagelist, |
330 | 326 | mmap_return_errors, &state); |
331 | 327 | } |
... | ... | @@ -383,8 +379,9 @@ |
383 | 379 | if (xen_feature(XENFEAT_auto_translated_physmap)) |
384 | 380 | return -ENOSYS; |
385 | 381 | |
386 | - /* DONTCOPY is essential for Xen as copy_page_range is broken. */ | |
387 | - vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY; | |
382 | + /* DONTCOPY is essential for Xen because copy_page_range doesn't know | |
383 | + * how to recreate these mappings */ | |
384 | + vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP; | |
388 | 385 | vma->vm_ops = &privcmd_vm_ops; |
389 | 386 | vma->vm_private_data = NULL; |
390 | 387 |
drivers/xen/xenfs/super.c
... | ... | @@ -12,8 +12,6 @@ |
12 | 12 | #include <linux/module.h> |
13 | 13 | #include <linux/fs.h> |
14 | 14 | #include <linux/magic.h> |
15 | -#include <linux/mm.h> | |
16 | -#include <linux/backing-dev.h> | |
17 | 15 | |
18 | 16 | #include <xen/xen.h> |
19 | 17 | |
20 | 18 | |
... | ... | @@ -24,28 +22,12 @@ |
24 | 22 | MODULE_DESCRIPTION("Xen filesystem"); |
25 | 23 | MODULE_LICENSE("GPL"); |
26 | 24 | |
27 | -static int xenfs_set_page_dirty(struct page *page) | |
28 | -{ | |
29 | - return !TestSetPageDirty(page); | |
30 | -} | |
31 | - | |
32 | -static const struct address_space_operations xenfs_aops = { | |
33 | - .set_page_dirty = xenfs_set_page_dirty, | |
34 | -}; | |
35 | - | |
36 | -static struct backing_dev_info xenfs_backing_dev_info = { | |
37 | - .ra_pages = 0, /* No readahead */ | |
38 | - .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, | |
39 | -}; | |
40 | - | |
41 | 25 | static struct inode *xenfs_make_inode(struct super_block *sb, int mode) |
42 | 26 | { |
43 | 27 | struct inode *ret = new_inode(sb); |
44 | 28 | |
45 | 29 | if (ret) { |
46 | 30 | ret->i_mode = mode; |
47 | - ret->i_mapping->a_ops = &xenfs_aops; | |
48 | - ret->i_mapping->backing_dev_info = &xenfs_backing_dev_info; | |
49 | 31 | ret->i_uid = ret->i_gid = 0; |
50 | 32 | ret->i_blocks = 0; |
51 | 33 | ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; |
... | ... | @@ -121,9 +103,9 @@ |
121 | 103 | return rc; |
122 | 104 | } |
123 | 105 | |
124 | -static int xenfs_mount(struct file_system_type *fs_type, | |
125 | - int flags, const char *dev_name, | |
126 | - void *data) | |
106 | +static struct dentry *xenfs_mount(struct file_system_type *fs_type, | |
107 | + int flags, const char *dev_name, | |
108 | + void *data) | |
127 | 109 | { |
128 | 110 | return mount_single(fs_type, flags, data, xenfs_fill_super); |
129 | 111 | } |
130 | 112 | |
... | ... | @@ -137,25 +119,11 @@ |
137 | 119 | |
138 | 120 | static int __init xenfs_init(void) |
139 | 121 | { |
140 | - int err; | |
141 | - if (!xen_domain()) { | |
142 | - printk(KERN_INFO "xenfs: not registering filesystem on non-xen platform\n"); | |
143 | - return 0; | |
144 | - } | |
122 | + if (xen_domain()) | |
123 | + return register_filesystem(&xenfs_type); | |
145 | 124 | |
146 | - err = register_filesystem(&xenfs_type); | |
147 | - if (err) { | |
148 | - printk(KERN_ERR "xenfs: Unable to register filesystem!\n"); | |
149 | - goto out; | |
150 | - } | |
151 | - | |
152 | - err = bdi_init(&xenfs_backing_dev_info); | |
153 | - if (err) | |
154 | - unregister_filesystem(&xenfs_type); | |
155 | - | |
156 | - out: | |
157 | - | |
158 | - return err; | |
125 | + printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n"); | |
126 | + return 0; | |
159 | 127 | } |
160 | 128 | |
161 | 129 | static void __exit xenfs_exit(void) |
include/xen/interface/memory.h
... | ... | @@ -141,6 +141,19 @@ |
141 | 141 | DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list); |
142 | 142 | |
143 | 143 | /* |
144 | + * Returns the location in virtual address space of the machine_to_phys | |
145 | + * mapping table. Architectures which do not have a m2p table, or which do not | |
146 | + * map it by default into guest address space, do not implement this command. | |
147 | + * arg == addr of xen_machphys_mapping_t. | |
148 | + */ | |
149 | +#define XENMEM_machphys_mapping 12 | |
150 | +struct xen_machphys_mapping { | |
151 | + unsigned long v_start, v_end; /* Start and end virtual addresses. */ | |
152 | + unsigned long max_mfn; /* Maximum MFN that can be looked up. */ | |
153 | +}; | |
154 | +DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mapping_t); | |
155 | + | |
156 | +/* | |
144 | 157 | * Sets the GPFN at which a particular page appears in the specified guest's |
145 | 158 | * pseudophysical address space. |
146 | 159 | * arg == addr of xen_add_to_physmap_t. |
include/xen/page.h
include/xen/privcmd.h