diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-26 14:42:25 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-26 14:42:25 -0500 |
commit | 4fe5e199ebcd82a05c7446e7e6b85027358dc274 (patch) | |
tree | 9a98fc2a40abd0fcdfe18108625f298f09253ef7 | |
parent | 02a5fec18297bb6991f5bc5ebc7e73fa6810809d (diff) | |
parent | 8620015499101090ae275bf11e9bc2f9febfdf08 (diff) |
Merge tag 'for-linus-4.4-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip
Pull xen bug fixes from David Vrabel:
- Fix gntdev and numa balancing.
- Fix x86 boot crash due to unallocated legacy irq descs.
- Fix overflow in evtchn device when > 1024 event channels.
* tag 'for-linus-4.4-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
xen/evtchn: dynamically grow pending event channel ring
xen/events: Always allocate legacy interrupts on PV guests
xen/gntdev: Grant maps should not be subject to NUMA balancing
-rw-r--r-- | arch/arm/include/asm/irq.h | 5 | ||||
-rw-r--r-- | arch/arm64/include/asm/irq.h | 5 | ||||
-rw-r--r-- | drivers/xen/events/events_base.c | 5 | ||||
-rw-r--r-- | drivers/xen/evtchn.c | 123 | ||||
-rw-r--r-- | drivers/xen/gntdev.c | 2 |
5 files changed, 121 insertions, 19 deletions
diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h index be1d07d59ee9..1bd9510de1b9 100644 --- a/arch/arm/include/asm/irq.h +++ b/arch/arm/include/asm/irq.h | |||
@@ -40,6 +40,11 @@ extern void arch_trigger_all_cpu_backtrace(bool); | |||
40 | #define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x) | 40 | #define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x) |
41 | #endif | 41 | #endif |
42 | 42 | ||
43 | static inline int nr_legacy_irqs(void) | ||
44 | { | ||
45 | return NR_IRQS_LEGACY; | ||
46 | } | ||
47 | |||
43 | #endif | 48 | #endif |
44 | 49 | ||
45 | #endif | 50 | #endif |
diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h index 23eb450b820b..8e8d30684392 100644 --- a/arch/arm64/include/asm/irq.h +++ b/arch/arm64/include/asm/irq.h | |||
@@ -7,4 +7,9 @@ struct pt_regs; | |||
7 | 7 | ||
8 | extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); | 8 | extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); |
9 | 9 | ||
10 | static inline int nr_legacy_irqs(void) | ||
11 | { | ||
12 | return 0; | ||
13 | } | ||
14 | |||
10 | #endif | 15 | #endif |
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 849500e4e14d..524c22146429 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
40 | #include <asm/idle.h> | 40 | #include <asm/idle.h> |
41 | #include <asm/io_apic.h> | 41 | #include <asm/io_apic.h> |
42 | #include <asm/i8259.h> | ||
42 | #include <asm/xen/pci.h> | 43 | #include <asm/xen/pci.h> |
43 | #endif | 44 | #endif |
44 | #include <asm/sync_bitops.h> | 45 | #include <asm/sync_bitops.h> |
@@ -420,7 +421,7 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi) | |||
420 | return xen_allocate_irq_dynamic(); | 421 | return xen_allocate_irq_dynamic(); |
421 | 422 | ||
422 | /* Legacy IRQ descriptors are already allocated by the arch. */ | 423 | /* Legacy IRQ descriptors are already allocated by the arch. */ |
423 | if (gsi < NR_IRQS_LEGACY) | 424 | if (gsi < nr_legacy_irqs()) |
424 | irq = gsi; | 425 | irq = gsi; |
425 | else | 426 | else |
426 | irq = irq_alloc_desc_at(gsi, -1); | 427 | irq = irq_alloc_desc_at(gsi, -1); |
@@ -446,7 +447,7 @@ static void xen_free_irq(unsigned irq) | |||
446 | kfree(info); | 447 | kfree(info); |
447 | 448 | ||
448 | /* Legacy IRQ descriptors are managed by the arch. */ | 449 | /* Legacy IRQ descriptors are managed by the arch. */ |
449 | if (irq < NR_IRQS_LEGACY) | 450 | if (irq < nr_legacy_irqs()) |
450 | return; | 451 | return; |
451 | 452 | ||
452 | irq_free_desc(irq); | 453 | irq_free_desc(irq); |
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index 00f40f051d95..38272ad24551 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c | |||
@@ -49,6 +49,8 @@ | |||
49 | #include <linux/init.h> | 49 | #include <linux/init.h> |
50 | #include <linux/mutex.h> | 50 | #include <linux/mutex.h> |
51 | #include <linux/cpu.h> | 51 | #include <linux/cpu.h> |
52 | #include <linux/mm.h> | ||
53 | #include <linux/vmalloc.h> | ||
52 | 54 | ||
53 | #include <xen/xen.h> | 55 | #include <xen/xen.h> |
54 | #include <xen/events.h> | 56 | #include <xen/events.h> |
@@ -58,10 +60,10 @@ | |||
58 | struct per_user_data { | 60 | struct per_user_data { |
59 | struct mutex bind_mutex; /* serialize bind/unbind operations */ | 61 | struct mutex bind_mutex; /* serialize bind/unbind operations */ |
60 | struct rb_root evtchns; | 62 | struct rb_root evtchns; |
63 | unsigned int nr_evtchns; | ||
61 | 64 | ||
62 | /* Notification ring, accessed via /dev/xen/evtchn. */ | 65 | /* Notification ring, accessed via /dev/xen/evtchn. */ |
63 | #define EVTCHN_RING_SIZE (PAGE_SIZE / sizeof(evtchn_port_t)) | 66 | unsigned int ring_size; |
64 | #define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1)) | ||
65 | evtchn_port_t *ring; | 67 | evtchn_port_t *ring; |
66 | unsigned int ring_cons, ring_prod, ring_overflow; | 68 | unsigned int ring_cons, ring_prod, ring_overflow; |
67 | struct mutex ring_cons_mutex; /* protect against concurrent readers */ | 69 | struct mutex ring_cons_mutex; /* protect against concurrent readers */ |
@@ -80,10 +82,41 @@ struct user_evtchn { | |||
80 | bool enabled; | 82 | bool enabled; |
81 | }; | 83 | }; |
82 | 84 | ||
85 | static evtchn_port_t *evtchn_alloc_ring(unsigned int size) | ||
86 | { | ||
87 | evtchn_port_t *ring; | ||
88 | size_t s = size * sizeof(*ring); | ||
89 | |||
90 | ring = kmalloc(s, GFP_KERNEL); | ||
91 | if (!ring) | ||
92 | ring = vmalloc(s); | ||
93 | |||
94 | return ring; | ||
95 | } | ||
96 | |||
97 | static void evtchn_free_ring(evtchn_port_t *ring) | ||
98 | { | ||
99 | kvfree(ring); | ||
100 | } | ||
101 | |||
102 | static unsigned int evtchn_ring_offset(struct per_user_data *u, | ||
103 | unsigned int idx) | ||
104 | { | ||
105 | return idx & (u->ring_size - 1); | ||
106 | } | ||
107 | |||
108 | static evtchn_port_t *evtchn_ring_entry(struct per_user_data *u, | ||
109 | unsigned int idx) | ||
110 | { | ||
111 | return u->ring + evtchn_ring_offset(u, idx); | ||
112 | } | ||
113 | |||
83 | static int add_evtchn(struct per_user_data *u, struct user_evtchn *evtchn) | 114 | static int add_evtchn(struct per_user_data *u, struct user_evtchn *evtchn) |
84 | { | 115 | { |
85 | struct rb_node **new = &(u->evtchns.rb_node), *parent = NULL; | 116 | struct rb_node **new = &(u->evtchns.rb_node), *parent = NULL; |
86 | 117 | ||
118 | u->nr_evtchns++; | ||
119 | |||
87 | while (*new) { | 120 | while (*new) { |
88 | struct user_evtchn *this; | 121 | struct user_evtchn *this; |
89 | 122 | ||
@@ -107,6 +140,7 @@ static int add_evtchn(struct per_user_data *u, struct user_evtchn *evtchn) | |||
107 | 140 | ||
108 | static void del_evtchn(struct per_user_data *u, struct user_evtchn *evtchn) | 141 | static void del_evtchn(struct per_user_data *u, struct user_evtchn *evtchn) |
109 | { | 142 | { |
143 | u->nr_evtchns--; | ||
110 | rb_erase(&evtchn->node, &u->evtchns); | 144 | rb_erase(&evtchn->node, &u->evtchns); |
111 | kfree(evtchn); | 145 | kfree(evtchn); |
112 | } | 146 | } |
@@ -144,8 +178,8 @@ static irqreturn_t evtchn_interrupt(int irq, void *data) | |||
144 | 178 | ||
145 | spin_lock(&u->ring_prod_lock); | 179 | spin_lock(&u->ring_prod_lock); |
146 | 180 | ||
147 | if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { | 181 | if ((u->ring_prod - u->ring_cons) < u->ring_size) { |
148 | u->ring[EVTCHN_RING_MASK(u->ring_prod)] = evtchn->port; | 182 | *evtchn_ring_entry(u, u->ring_prod) = evtchn->port; |
149 | wmb(); /* Ensure ring contents visible */ | 183 | wmb(); /* Ensure ring contents visible */ |
150 | if (u->ring_cons == u->ring_prod++) { | 184 | if (u->ring_cons == u->ring_prod++) { |
151 | wake_up_interruptible(&u->evtchn_wait); | 185 | wake_up_interruptible(&u->evtchn_wait); |
@@ -200,10 +234,10 @@ static ssize_t evtchn_read(struct file *file, char __user *buf, | |||
200 | } | 234 | } |
201 | 235 | ||
202 | /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */ | 236 | /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */ |
203 | if (((c ^ p) & EVTCHN_RING_SIZE) != 0) { | 237 | if (((c ^ p) & u->ring_size) != 0) { |
204 | bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * | 238 | bytes1 = (u->ring_size - evtchn_ring_offset(u, c)) * |
205 | sizeof(evtchn_port_t); | 239 | sizeof(evtchn_port_t); |
206 | bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t); | 240 | bytes2 = evtchn_ring_offset(u, p) * sizeof(evtchn_port_t); |
207 | } else { | 241 | } else { |
208 | bytes1 = (p - c) * sizeof(evtchn_port_t); | 242 | bytes1 = (p - c) * sizeof(evtchn_port_t); |
209 | bytes2 = 0; | 243 | bytes2 = 0; |
@@ -219,7 +253,7 @@ static ssize_t evtchn_read(struct file *file, char __user *buf, | |||
219 | 253 | ||
220 | rc = -EFAULT; | 254 | rc = -EFAULT; |
221 | rmb(); /* Ensure that we see the port before we copy it. */ | 255 | rmb(); /* Ensure that we see the port before we copy it. */ |
222 | if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) || | 256 | if (copy_to_user(buf, evtchn_ring_entry(u, c), bytes1) || |
223 | ((bytes2 != 0) && | 257 | ((bytes2 != 0) && |
224 | copy_to_user(&buf[bytes1], &u->ring[0], bytes2))) | 258 | copy_to_user(&buf[bytes1], &u->ring[0], bytes2))) |
225 | goto unlock_out; | 259 | goto unlock_out; |
@@ -278,6 +312,66 @@ static ssize_t evtchn_write(struct file *file, const char __user *buf, | |||
278 | return rc; | 312 | return rc; |
279 | } | 313 | } |
280 | 314 | ||
315 | static int evtchn_resize_ring(struct per_user_data *u) | ||
316 | { | ||
317 | unsigned int new_size; | ||
318 | evtchn_port_t *new_ring, *old_ring; | ||
319 | unsigned int p, c; | ||
320 | |||
321 | /* | ||
322 | * Ensure the ring is large enough to capture all possible | ||
323 | * events. i.e., one free slot for each bound event. | ||
324 | */ | ||
325 | if (u->nr_evtchns <= u->ring_size) | ||
326 | return 0; | ||
327 | |||
328 | if (u->ring_size == 0) | ||
329 | new_size = 64; | ||
330 | else | ||
331 | new_size = 2 * u->ring_size; | ||
332 | |||
333 | new_ring = evtchn_alloc_ring(new_size); | ||
334 | if (!new_ring) | ||
335 | return -ENOMEM; | ||
336 | |||
337 | old_ring = u->ring; | ||
338 | |||
339 | /* | ||
340 | * Access to the ring contents is serialized by either the | ||
341 | * prod /or/ cons lock so take both when resizing. | ||
342 | */ | ||
343 | mutex_lock(&u->ring_cons_mutex); | ||
344 | spin_lock_irq(&u->ring_prod_lock); | ||
345 | |||
346 | /* | ||
347 | * Copy the old ring contents to the new ring. | ||
348 | * | ||
349 | * If the ring contents crosses the end of the current ring, | ||
350 | * it needs to be copied in two chunks. | ||
351 | * | ||
352 | * +---------+ +------------------+ | ||
353 | * |34567 12| -> | 1234567 | | ||
354 | * +-----p-c-+ +------------------+ | ||
355 | */ | ||
356 | p = evtchn_ring_offset(u, u->ring_prod); | ||
357 | c = evtchn_ring_offset(u, u->ring_cons); | ||
358 | if (p < c) { | ||
359 | memcpy(new_ring + c, u->ring + c, (u->ring_size - c) * sizeof(*u->ring)); | ||
360 | memcpy(new_ring + u->ring_size, u->ring, p * sizeof(*u->ring)); | ||
361 | } else | ||
362 | memcpy(new_ring + c, u->ring + c, (p - c) * sizeof(*u->ring)); | ||
363 | |||
364 | u->ring = new_ring; | ||
365 | u->ring_size = new_size; | ||
366 | |||
367 | spin_unlock_irq(&u->ring_prod_lock); | ||
368 | mutex_unlock(&u->ring_cons_mutex); | ||
369 | |||
370 | evtchn_free_ring(old_ring); | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | |||
281 | static int evtchn_bind_to_user(struct per_user_data *u, int port) | 375 | static int evtchn_bind_to_user(struct per_user_data *u, int port) |
282 | { | 376 | { |
283 | struct user_evtchn *evtchn; | 377 | struct user_evtchn *evtchn; |
@@ -305,6 +399,10 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port) | |||
305 | if (rc < 0) | 399 | if (rc < 0) |
306 | goto err; | 400 | goto err; |
307 | 401 | ||
402 | rc = evtchn_resize_ring(u); | ||
403 | if (rc < 0) | ||
404 | goto err; | ||
405 | |||
308 | rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, 0, | 406 | rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, 0, |
309 | u->name, evtchn); | 407 | u->name, evtchn); |
310 | if (rc < 0) | 408 | if (rc < 0) |
@@ -503,13 +601,6 @@ static int evtchn_open(struct inode *inode, struct file *filp) | |||
503 | 601 | ||
504 | init_waitqueue_head(&u->evtchn_wait); | 602 | init_waitqueue_head(&u->evtchn_wait); |
505 | 603 | ||
506 | u->ring = (evtchn_port_t *)__get_free_page(GFP_KERNEL); | ||
507 | if (u->ring == NULL) { | ||
508 | kfree(u->name); | ||
509 | kfree(u); | ||
510 | return -ENOMEM; | ||
511 | } | ||
512 | |||
513 | mutex_init(&u->bind_mutex); | 604 | mutex_init(&u->bind_mutex); |
514 | mutex_init(&u->ring_cons_mutex); | 605 | mutex_init(&u->ring_cons_mutex); |
515 | spin_lock_init(&u->ring_prod_lock); | 606 | spin_lock_init(&u->ring_prod_lock); |
@@ -532,7 +623,7 @@ static int evtchn_release(struct inode *inode, struct file *filp) | |||
532 | evtchn_unbind_from_user(u, evtchn); | 623 | evtchn_unbind_from_user(u, evtchn); |
533 | } | 624 | } |
534 | 625 | ||
535 | free_page((unsigned long)u->ring); | 626 | evtchn_free_ring(u->ring); |
536 | kfree(u->name); | 627 | kfree(u->name); |
537 | kfree(u); | 628 | kfree(u); |
538 | 629 | ||
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 2ea0b3b2a91d..1be5dd048622 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c | |||
@@ -804,7 +804,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) | |||
804 | 804 | ||
805 | vma->vm_ops = &gntdev_vmops; | 805 | vma->vm_ops = &gntdev_vmops; |
806 | 806 | ||
807 | vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; | 807 | vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO; |
808 | 808 | ||
809 | if (use_ptemod) | 809 | if (use_ptemod) |
810 | vma->vm_flags |= VM_DONTCOPY; | 810 | vma->vm_flags |= VM_DONTCOPY; |