aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen')
-rw-r--r--drivers/xen/Kconfig7
-rw-r--r--drivers/xen/Makefile2
-rw-r--r--drivers/xen/events.c77
-rw-r--r--drivers/xen/evtchn.c2
-rw-r--r--drivers/xen/gntalloc.c120
-rw-r--r--drivers/xen/gntdev.c31
-rw-r--r--drivers/xen/grant-table.c496
-rw-r--r--drivers/xen/privcmd.c (renamed from drivers/xen/xenfs/privcmd.c)41
-rw-r--r--drivers/xen/privcmd.h3
-rw-r--r--drivers/xen/xenbus/Makefile2
-rw-r--r--drivers/xen/xenbus/xenbus_comms.h4
-rw-r--r--drivers/xen/xenbus/xenbus_dev_backend.c89
-rw-r--r--drivers/xen/xenbus/xenbus_dev_frontend.c (renamed from drivers/xen/xenfs/xenbus.c)38
-rw-r--r--drivers/xen/xenfs/Makefile2
-rw-r--r--drivers/xen/xenfs/super.c6
-rw-r--r--drivers/xen/xenfs/xenfs.h2
16 files changed, 831 insertions, 91 deletions
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 8795480c2350..a1ced521cf74 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -86,6 +86,7 @@ config XEN_BACKEND
86 86
87config XENFS 87config XENFS
88 tristate "Xen filesystem" 88 tristate "Xen filesystem"
89 select XEN_PRIVCMD
89 default y 90 default y
90 help 91 help
91 The xen filesystem provides a way for domains to share 92 The xen filesystem provides a way for domains to share
@@ -171,4 +172,10 @@ config XEN_PCIDEV_BACKEND
171 xen-pciback.hide=(03:00.0)(04:00.0) 172 xen-pciback.hide=(03:00.0)(04:00.0)
172 173
173 If in doubt, say m. 174 If in doubt, say m.
175
176config XEN_PRIVCMD
177 tristate
178 depends on XEN
179 default m
180
174endmenu 181endmenu
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 974fffdf22b2..aa31337192cc 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -19,7 +19,9 @@ obj-$(CONFIG_XEN_TMEM) += tmem.o
19obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o 19obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o
20obj-$(CONFIG_XEN_DOM0) += pci.o 20obj-$(CONFIG_XEN_DOM0) += pci.o
21obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/ 21obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/
22obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o
22 23
23xen-evtchn-y := evtchn.o 24xen-evtchn-y := evtchn.o
24xen-gntdev-y := gntdev.o 25xen-gntdev-y := gntdev.o
25xen-gntalloc-y := gntalloc.o 26xen-gntalloc-y := gntalloc.o
27xen-privcmd-y := privcmd.o
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 6e075cdd0c6b..e5e5812a1014 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -87,6 +87,7 @@ enum xen_irq_type {
87 */ 87 */
88struct irq_info { 88struct irq_info {
89 struct list_head list; 89 struct list_head list;
90 int refcnt;
90 enum xen_irq_type type; /* type */ 91 enum xen_irq_type type; /* type */
91 unsigned irq; 92 unsigned irq;
92 unsigned short evtchn; /* event channel */ 93 unsigned short evtchn; /* event channel */
@@ -406,6 +407,7 @@ static void xen_irq_init(unsigned irq)
406 panic("Unable to allocate metadata for IRQ%d\n", irq); 407 panic("Unable to allocate metadata for IRQ%d\n", irq);
407 408
408 info->type = IRQT_UNBOUND; 409 info->type = IRQT_UNBOUND;
410 info->refcnt = -1;
409 411
410 irq_set_handler_data(irq, info); 412 irq_set_handler_data(irq, info);
411 413
@@ -469,6 +471,8 @@ static void xen_free_irq(unsigned irq)
469 471
470 irq_set_handler_data(irq, NULL); 472 irq_set_handler_data(irq, NULL);
471 473
474 WARN_ON(info->refcnt > 0);
475
472 kfree(info); 476 kfree(info);
473 477
474 /* Legacy IRQ descriptors are managed by the arch. */ 478 /* Legacy IRQ descriptors are managed by the arch. */
@@ -637,7 +641,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
637 if (irq != -1) { 641 if (irq != -1) {
638 printk(KERN_INFO "xen_map_pirq_gsi: returning irq %d for gsi %u\n", 642 printk(KERN_INFO "xen_map_pirq_gsi: returning irq %d for gsi %u\n",
639 irq, gsi); 643 irq, gsi);
640 goto out; /* XXX need refcount? */ 644 goto out;
641 } 645 }
642 646
643 irq = xen_allocate_irq_gsi(gsi); 647 irq = xen_allocate_irq_gsi(gsi);
@@ -939,9 +943,16 @@ static void unbind_from_irq(unsigned int irq)
939{ 943{
940 struct evtchn_close close; 944 struct evtchn_close close;
941 int evtchn = evtchn_from_irq(irq); 945 int evtchn = evtchn_from_irq(irq);
946 struct irq_info *info = irq_get_handler_data(irq);
942 947
943 mutex_lock(&irq_mapping_update_lock); 948 mutex_lock(&irq_mapping_update_lock);
944 949
950 if (info->refcnt > 0) {
951 info->refcnt--;
952 if (info->refcnt != 0)
953 goto done;
954 }
955
945 if (VALID_EVTCHN(evtchn)) { 956 if (VALID_EVTCHN(evtchn)) {
946 close.port = evtchn; 957 close.port = evtchn;
947 if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) 958 if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
@@ -970,6 +981,7 @@ static void unbind_from_irq(unsigned int irq)
970 981
971 xen_free_irq(irq); 982 xen_free_irq(irq);
972 983
984 done:
973 mutex_unlock(&irq_mapping_update_lock); 985 mutex_unlock(&irq_mapping_update_lock);
974} 986}
975 987
@@ -1065,6 +1077,69 @@ void unbind_from_irqhandler(unsigned int irq, void *dev_id)
1065} 1077}
1066EXPORT_SYMBOL_GPL(unbind_from_irqhandler); 1078EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
1067 1079
1080int evtchn_make_refcounted(unsigned int evtchn)
1081{
1082 int irq = evtchn_to_irq[evtchn];
1083 struct irq_info *info;
1084
1085 if (irq == -1)
1086 return -ENOENT;
1087
1088 info = irq_get_handler_data(irq);
1089
1090 if (!info)
1091 return -ENOENT;
1092
1093 WARN_ON(info->refcnt != -1);
1094
1095 info->refcnt = 1;
1096
1097 return 0;
1098}
1099EXPORT_SYMBOL_GPL(evtchn_make_refcounted);
1100
1101int evtchn_get(unsigned int evtchn)
1102{
1103 int irq;
1104 struct irq_info *info;
1105 int err = -ENOENT;
1106
1107 if (evtchn >= NR_EVENT_CHANNELS)
1108 return -EINVAL;
1109
1110 mutex_lock(&irq_mapping_update_lock);
1111
1112 irq = evtchn_to_irq[evtchn];
1113 if (irq == -1)
1114 goto done;
1115
1116 info = irq_get_handler_data(irq);
1117
1118 if (!info)
1119 goto done;
1120
1121 err = -EINVAL;
1122 if (info->refcnt <= 0)
1123 goto done;
1124
1125 info->refcnt++;
1126 err = 0;
1127 done:
1128 mutex_unlock(&irq_mapping_update_lock);
1129
1130 return err;
1131}
1132EXPORT_SYMBOL_GPL(evtchn_get);
1133
1134void evtchn_put(unsigned int evtchn)
1135{
1136 int irq = evtchn_to_irq[evtchn];
1137 if (WARN_ON(irq == -1))
1138 return;
1139 unbind_from_irq(irq);
1140}
1141EXPORT_SYMBOL_GPL(evtchn_put);
1142
1068void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector) 1143void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
1069{ 1144{
1070 int irq = per_cpu(ipi_to_irq, cpu)[vector]; 1145 int irq = per_cpu(ipi_to_irq, cpu)[vector];
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
index dbc13e94b612..b1f60a0c0bea 100644
--- a/drivers/xen/evtchn.c
+++ b/drivers/xen/evtchn.c
@@ -268,7 +268,7 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port)
268 rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, 268 rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED,
269 u->name, (void *)(unsigned long)port); 269 u->name, (void *)(unsigned long)port);
270 if (rc >= 0) 270 if (rc >= 0)
271 rc = 0; 271 rc = evtchn_make_refcounted(port);
272 272
273 return rc; 273 return rc;
274} 274}
diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c
index e1c4c6e5b469..e2400c8963fa 100644
--- a/drivers/xen/gntalloc.c
+++ b/drivers/xen/gntalloc.c
@@ -74,7 +74,7 @@ MODULE_PARM_DESC(limit, "Maximum number of grants that may be allocated by "
74 "the gntalloc device"); 74 "the gntalloc device");
75 75
76static LIST_HEAD(gref_list); 76static LIST_HEAD(gref_list);
77static DEFINE_SPINLOCK(gref_lock); 77static DEFINE_MUTEX(gref_mutex);
78static int gref_size; 78static int gref_size;
79 79
80struct notify_info { 80struct notify_info {
@@ -99,6 +99,12 @@ struct gntalloc_file_private_data {
99 uint64_t index; 99 uint64_t index;
100}; 100};
101 101
102struct gntalloc_vma_private_data {
103 struct gntalloc_gref *gref;
104 int users;
105 int count;
106};
107
102static void __del_gref(struct gntalloc_gref *gref); 108static void __del_gref(struct gntalloc_gref *gref);
103 109
104static void do_cleanup(void) 110static void do_cleanup(void)
@@ -143,15 +149,15 @@ static int add_grefs(struct ioctl_gntalloc_alloc_gref *op,
143 } 149 }
144 150
145 /* Add to gref lists. */ 151 /* Add to gref lists. */
146 spin_lock(&gref_lock); 152 mutex_lock(&gref_mutex);
147 list_splice_tail(&queue_gref, &gref_list); 153 list_splice_tail(&queue_gref, &gref_list);
148 list_splice_tail(&queue_file, &priv->list); 154 list_splice_tail(&queue_file, &priv->list);
149 spin_unlock(&gref_lock); 155 mutex_unlock(&gref_mutex);
150 156
151 return 0; 157 return 0;
152 158
153undo: 159undo:
154 spin_lock(&gref_lock); 160 mutex_lock(&gref_mutex);
155 gref_size -= (op->count - i); 161 gref_size -= (op->count - i);
156 162
157 list_for_each_entry(gref, &queue_file, next_file) { 163 list_for_each_entry(gref, &queue_file, next_file) {
@@ -167,7 +173,7 @@ undo:
167 */ 173 */
168 if (unlikely(!list_empty(&queue_gref))) 174 if (unlikely(!list_empty(&queue_gref)))
169 list_splice_tail(&queue_gref, &gref_list); 175 list_splice_tail(&queue_gref, &gref_list);
170 spin_unlock(&gref_lock); 176 mutex_unlock(&gref_mutex);
171 return rc; 177 return rc;
172} 178}
173 179
@@ -178,8 +184,10 @@ static void __del_gref(struct gntalloc_gref *gref)
178 tmp[gref->notify.pgoff] = 0; 184 tmp[gref->notify.pgoff] = 0;
179 kunmap(gref->page); 185 kunmap(gref->page);
180 } 186 }
181 if (gref->notify.flags & UNMAP_NOTIFY_SEND_EVENT) 187 if (gref->notify.flags & UNMAP_NOTIFY_SEND_EVENT) {
182 notify_remote_via_evtchn(gref->notify.event); 188 notify_remote_via_evtchn(gref->notify.event);
189 evtchn_put(gref->notify.event);
190 }
183 191
184 gref->notify.flags = 0; 192 gref->notify.flags = 0;
185 193
@@ -189,6 +197,8 @@ static void __del_gref(struct gntalloc_gref *gref)
189 197
190 if (!gnttab_end_foreign_access_ref(gref->gref_id, 0)) 198 if (!gnttab_end_foreign_access_ref(gref->gref_id, 0))
191 return; 199 return;
200
201 gnttab_free_grant_reference(gref->gref_id);
192 } 202 }
193 203
194 gref_size--; 204 gref_size--;
@@ -251,7 +261,7 @@ static int gntalloc_release(struct inode *inode, struct file *filp)
251 261
252 pr_debug("%s: priv %p\n", __func__, priv); 262 pr_debug("%s: priv %p\n", __func__, priv);
253 263
254 spin_lock(&gref_lock); 264 mutex_lock(&gref_mutex);
255 while (!list_empty(&priv->list)) { 265 while (!list_empty(&priv->list)) {
256 gref = list_entry(priv->list.next, 266 gref = list_entry(priv->list.next,
257 struct gntalloc_gref, next_file); 267 struct gntalloc_gref, next_file);
@@ -261,7 +271,7 @@ static int gntalloc_release(struct inode *inode, struct file *filp)
261 __del_gref(gref); 271 __del_gref(gref);
262 } 272 }
263 kfree(priv); 273 kfree(priv);
264 spin_unlock(&gref_lock); 274 mutex_unlock(&gref_mutex);
265 275
266 return 0; 276 return 0;
267} 277}
@@ -286,21 +296,21 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
286 goto out; 296 goto out;
287 } 297 }
288 298
289 spin_lock(&gref_lock); 299 mutex_lock(&gref_mutex);
290 /* Clean up pages that were at zero (local) users but were still mapped 300 /* Clean up pages that were at zero (local) users but were still mapped
291 * by remote domains. Since those pages count towards the limit that we 301 * by remote domains. Since those pages count towards the limit that we
292 * are about to enforce, removing them here is a good idea. 302 * are about to enforce, removing them here is a good idea.
293 */ 303 */
294 do_cleanup(); 304 do_cleanup();
295 if (gref_size + op.count > limit) { 305 if (gref_size + op.count > limit) {
296 spin_unlock(&gref_lock); 306 mutex_unlock(&gref_mutex);
297 rc = -ENOSPC; 307 rc = -ENOSPC;
298 goto out_free; 308 goto out_free;
299 } 309 }
300 gref_size += op.count; 310 gref_size += op.count;
301 op.index = priv->index; 311 op.index = priv->index;
302 priv->index += op.count * PAGE_SIZE; 312 priv->index += op.count * PAGE_SIZE;
303 spin_unlock(&gref_lock); 313 mutex_unlock(&gref_mutex);
304 314
305 rc = add_grefs(&op, gref_ids, priv); 315 rc = add_grefs(&op, gref_ids, priv);
306 if (rc < 0) 316 if (rc < 0)
@@ -343,7 +353,7 @@ static long gntalloc_ioctl_dealloc(struct gntalloc_file_private_data *priv,
343 goto dealloc_grant_out; 353 goto dealloc_grant_out;
344 } 354 }
345 355
346 spin_lock(&gref_lock); 356 mutex_lock(&gref_mutex);
347 gref = find_grefs(priv, op.index, op.count); 357 gref = find_grefs(priv, op.index, op.count);
348 if (gref) { 358 if (gref) {
349 /* Remove from the file list only, and decrease reference count. 359 /* Remove from the file list only, and decrease reference count.
@@ -363,7 +373,7 @@ static long gntalloc_ioctl_dealloc(struct gntalloc_file_private_data *priv,
363 373
364 do_cleanup(); 374 do_cleanup();
365 375
366 spin_unlock(&gref_lock); 376 mutex_unlock(&gref_mutex);
367dealloc_grant_out: 377dealloc_grant_out:
368 return rc; 378 return rc;
369} 379}
@@ -383,7 +393,7 @@ static long gntalloc_ioctl_unmap_notify(struct gntalloc_file_private_data *priv,
383 index = op.index & ~(PAGE_SIZE - 1); 393 index = op.index & ~(PAGE_SIZE - 1);
384 pgoff = op.index & (PAGE_SIZE - 1); 394 pgoff = op.index & (PAGE_SIZE - 1);
385 395
386 spin_lock(&gref_lock); 396 mutex_lock(&gref_mutex);
387 397
388 gref = find_grefs(priv, index, 1); 398 gref = find_grefs(priv, index, 1);
389 if (!gref) { 399 if (!gref) {
@@ -396,12 +406,30 @@ static long gntalloc_ioctl_unmap_notify(struct gntalloc_file_private_data *priv,
396 goto unlock_out; 406 goto unlock_out;
397 } 407 }
398 408
409 /* We need to grab a reference to the event channel we are going to use
410 * to send the notify before releasing the reference we may already have
411 * (if someone has called this ioctl twice). This is required so that
412 * it is possible to change the clear_byte part of the notification
413 * without disturbing the event channel part, which may now be the last
414 * reference to that event channel.
415 */
416 if (op.action & UNMAP_NOTIFY_SEND_EVENT) {
417 if (evtchn_get(op.event_channel_port)) {
418 rc = -EINVAL;
419 goto unlock_out;
420 }
421 }
422
423 if (gref->notify.flags & UNMAP_NOTIFY_SEND_EVENT)
424 evtchn_put(gref->notify.event);
425
399 gref->notify.flags = op.action; 426 gref->notify.flags = op.action;
400 gref->notify.pgoff = pgoff; 427 gref->notify.pgoff = pgoff;
401 gref->notify.event = op.event_channel_port; 428 gref->notify.event = op.event_channel_port;
402 rc = 0; 429 rc = 0;
430
403 unlock_out: 431 unlock_out:
404 spin_unlock(&gref_lock); 432 mutex_unlock(&gref_mutex);
405 return rc; 433 return rc;
406} 434}
407 435
@@ -429,26 +457,40 @@ static long gntalloc_ioctl(struct file *filp, unsigned int cmd,
429 457
430static void gntalloc_vma_open(struct vm_area_struct *vma) 458static void gntalloc_vma_open(struct vm_area_struct *vma)
431{ 459{
432 struct gntalloc_gref *gref = vma->vm_private_data; 460 struct gntalloc_vma_private_data *priv = vma->vm_private_data;
433 if (!gref) 461
462 if (!priv)
434 return; 463 return;
435 464
436 spin_lock(&gref_lock); 465 mutex_lock(&gref_mutex);
437 gref->users++; 466 priv->users++;
438 spin_unlock(&gref_lock); 467 mutex_unlock(&gref_mutex);
439} 468}
440 469
441static void gntalloc_vma_close(struct vm_area_struct *vma) 470static void gntalloc_vma_close(struct vm_area_struct *vma)
442{ 471{
443 struct gntalloc_gref *gref = vma->vm_private_data; 472 struct gntalloc_vma_private_data *priv = vma->vm_private_data;
444 if (!gref) 473 struct gntalloc_gref *gref, *next;
474 int i;
475
476 if (!priv)
445 return; 477 return;
446 478
447 spin_lock(&gref_lock); 479 mutex_lock(&gref_mutex);
448 gref->users--; 480 priv->users--;
449 if (gref->users == 0) 481 if (priv->users == 0) {
450 __del_gref(gref); 482 gref = priv->gref;
451 spin_unlock(&gref_lock); 483 for (i = 0; i < priv->count; i++) {
484 gref->users--;
485 next = list_entry(gref->next_gref.next,
486 struct gntalloc_gref, next_gref);
487 if (gref->users == 0)
488 __del_gref(gref);
489 gref = next;
490 }
491 kfree(priv);
492 }
493 mutex_unlock(&gref_mutex);
452} 494}
453 495
454static struct vm_operations_struct gntalloc_vmops = { 496static struct vm_operations_struct gntalloc_vmops = {
@@ -459,19 +501,25 @@ static struct vm_operations_struct gntalloc_vmops = {
459static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma) 501static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma)
460{ 502{
461 struct gntalloc_file_private_data *priv = filp->private_data; 503 struct gntalloc_file_private_data *priv = filp->private_data;
504 struct gntalloc_vma_private_data *vm_priv;
462 struct gntalloc_gref *gref; 505 struct gntalloc_gref *gref;
463 int count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; 506 int count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
464 int rv, i; 507 int rv, i;
465 508
466 pr_debug("%s: priv %p, page %lu+%d\n", __func__,
467 priv, vma->vm_pgoff, count);
468
469 if (!(vma->vm_flags & VM_SHARED)) { 509 if (!(vma->vm_flags & VM_SHARED)) {
470 printk(KERN_ERR "%s: Mapping must be shared.\n", __func__); 510 printk(KERN_ERR "%s: Mapping must be shared.\n", __func__);
471 return -EINVAL; 511 return -EINVAL;
472 } 512 }
473 513
474 spin_lock(&gref_lock); 514 vm_priv = kmalloc(sizeof(*vm_priv), GFP_KERNEL);
515 if (!vm_priv)
516 return -ENOMEM;
517
518 mutex_lock(&gref_mutex);
519
520 pr_debug("%s: priv %p,%p, page %lu+%d\n", __func__,
521 priv, vm_priv, vma->vm_pgoff, count);
522
475 gref = find_grefs(priv, vma->vm_pgoff << PAGE_SHIFT, count); 523 gref = find_grefs(priv, vma->vm_pgoff << PAGE_SHIFT, count);
476 if (gref == NULL) { 524 if (gref == NULL) {
477 rv = -ENOENT; 525 rv = -ENOENT;
@@ -480,9 +528,13 @@ static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma)
480 goto out_unlock; 528 goto out_unlock;
481 } 529 }
482 530
483 vma->vm_private_data = gref; 531 vm_priv->gref = gref;
532 vm_priv->users = 1;
533 vm_priv->count = count;
534
535 vma->vm_private_data = vm_priv;
484 536
485 vma->vm_flags |= VM_RESERVED; 537 vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
486 538
487 vma->vm_ops = &gntalloc_vmops; 539 vma->vm_ops = &gntalloc_vmops;
488 540
@@ -499,7 +551,7 @@ static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma)
499 rv = 0; 551 rv = 0;
500 552
501out_unlock: 553out_unlock:
502 spin_unlock(&gref_lock); 554 mutex_unlock(&gref_mutex);
503 return rv; 555 return rv;
504} 556}
505 557
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index afca14d9042e..f52f661f8f82 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -193,8 +193,10 @@ static void gntdev_put_map(struct grant_map *map)
193 193
194 atomic_sub(map->count, &pages_mapped); 194 atomic_sub(map->count, &pages_mapped);
195 195
196 if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) 196 if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) {
197 notify_remote_via_evtchn(map->notify.event); 197 notify_remote_via_evtchn(map->notify.event);
198 evtchn_put(map->notify.event);
199 }
198 200
199 if (map->pages) { 201 if (map->pages) {
200 if (!use_ptemod) 202 if (!use_ptemod)
@@ -599,6 +601,8 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
599 struct ioctl_gntdev_unmap_notify op; 601 struct ioctl_gntdev_unmap_notify op;
600 struct grant_map *map; 602 struct grant_map *map;
601 int rc; 603 int rc;
604 int out_flags;
605 unsigned int out_event;
602 606
603 if (copy_from_user(&op, u, sizeof(op))) 607 if (copy_from_user(&op, u, sizeof(op)))
604 return -EFAULT; 608 return -EFAULT;
@@ -606,6 +610,21 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
606 if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT)) 610 if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT))
607 return -EINVAL; 611 return -EINVAL;
608 612
613 /* We need to grab a reference to the event channel we are going to use
614 * to send the notify before releasing the reference we may already have
615 * (if someone has called this ioctl twice). This is required so that
616 * it is possible to change the clear_byte part of the notification
617 * without disturbing the event channel part, which may now be the last
618 * reference to that event channel.
619 */
620 if (op.action & UNMAP_NOTIFY_SEND_EVENT) {
621 if (evtchn_get(op.event_channel_port))
622 return -EINVAL;
623 }
624
625 out_flags = op.action;
626 out_event = op.event_channel_port;
627
609 spin_lock(&priv->lock); 628 spin_lock(&priv->lock);
610 629
611 list_for_each_entry(map, &priv->maps, next) { 630 list_for_each_entry(map, &priv->maps, next) {
@@ -624,12 +643,22 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
624 goto unlock_out; 643 goto unlock_out;
625 } 644 }
626 645
646 out_flags = map->notify.flags;
647 out_event = map->notify.event;
648
627 map->notify.flags = op.action; 649 map->notify.flags = op.action;
628 map->notify.addr = op.index - (map->index << PAGE_SHIFT); 650 map->notify.addr = op.index - (map->index << PAGE_SHIFT);
629 map->notify.event = op.event_channel_port; 651 map->notify.event = op.event_channel_port;
652
630 rc = 0; 653 rc = 0;
654
631 unlock_out: 655 unlock_out:
632 spin_unlock(&priv->lock); 656 spin_unlock(&priv->lock);
657
658 /* Drop the reference to the event channel we did not save in the map */
659 if (out_flags & UNMAP_NOTIFY_SEND_EVENT)
660 evtchn_put(out_event);
661
633 return rc; 662 return rc;
634} 663}
635 664
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index bf1c094f4ebf..a3d0e1e278c1 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -44,16 +44,19 @@
44#include <xen/page.h> 44#include <xen/page.h>
45#include <xen/grant_table.h> 45#include <xen/grant_table.h>
46#include <xen/interface/memory.h> 46#include <xen/interface/memory.h>
47#include <xen/hvc-console.h>
47#include <asm/xen/hypercall.h> 48#include <asm/xen/hypercall.h>
48 49
49#include <asm/pgtable.h> 50#include <asm/pgtable.h>
50#include <asm/sync_bitops.h> 51#include <asm/sync_bitops.h>
51 52
52
53/* External tools reserve first few grant table entries. */ 53/* External tools reserve first few grant table entries. */
54#define NR_RESERVED_ENTRIES 8 54#define NR_RESERVED_ENTRIES 8
55#define GNTTAB_LIST_END 0xffffffff 55#define GNTTAB_LIST_END 0xffffffff
56#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(struct grant_entry)) 56#define GREFS_PER_GRANT_FRAME \
57(grant_table_version == 1 ? \
58(PAGE_SIZE / sizeof(struct grant_entry_v1)) : \
59(PAGE_SIZE / sizeof(union grant_entry_v2)))
57 60
58static grant_ref_t **gnttab_list; 61static grant_ref_t **gnttab_list;
59static unsigned int nr_grant_frames; 62static unsigned int nr_grant_frames;
@@ -64,13 +67,97 @@ static DEFINE_SPINLOCK(gnttab_list_lock);
64unsigned long xen_hvm_resume_frames; 67unsigned long xen_hvm_resume_frames;
65EXPORT_SYMBOL_GPL(xen_hvm_resume_frames); 68EXPORT_SYMBOL_GPL(xen_hvm_resume_frames);
66 69
67static struct grant_entry *shared; 70static union {
71 struct grant_entry_v1 *v1;
72 union grant_entry_v2 *v2;
73 void *addr;
74} gnttab_shared;
75
76/*This is a structure of function pointers for grant table*/
77struct gnttab_ops {
78 /*
79 * Mapping a list of frames for storing grant entries. Frames parameter
80 * is used to store grant table address when grant table being setup,
81 * nr_gframes is the number of frames to map grant table. Returning
82 * GNTST_okay means success and negative value means failure.
83 */
84 int (*map_frames)(unsigned long *frames, unsigned int nr_gframes);
85 /*
86 * Release a list of frames which are mapped in map_frames for grant
87 * entry status.
88 */
89 void (*unmap_frames)(void);
90 /*
91 * Introducing a valid entry into the grant table, granting the frame of
92 * this grant entry to domain for accessing or transfering. Ref
93 * parameter is reference of this introduced grant entry, domid is id of
94 * granted domain, frame is the page frame to be granted, and flags is
95 * status of the grant entry to be updated.
96 */
97 void (*update_entry)(grant_ref_t ref, domid_t domid,
98 unsigned long frame, unsigned flags);
99 /*
100 * Stop granting a grant entry to domain for accessing. Ref parameter is
101 * reference of a grant entry whose grant access will be stopped,
102 * readonly is not in use in this function. If the grant entry is
103 * currently mapped for reading or writing, just return failure(==0)
104 * directly and don't tear down the grant access. Otherwise, stop grant
105 * access for this entry and return success(==1).
106 */
107 int (*end_foreign_access_ref)(grant_ref_t ref, int readonly);
108 /*
109 * Stop granting a grant entry to domain for transfer. Ref parameter is
110 * reference of a grant entry whose grant transfer will be stopped. If
111 * tranfer has not started, just reclaim the grant entry and return
112 * failure(==0). Otherwise, wait for the transfer to complete and then
113 * return the frame.
114 */
115 unsigned long (*end_foreign_transfer_ref)(grant_ref_t ref);
116 /*
117 * Query the status of a grant entry. Ref parameter is reference of
118 * queried grant entry, return value is the status of queried entry.
119 * Detailed status(writing/reading) can be gotten from the return value
120 * by bit operations.
121 */
122 int (*query_foreign_access)(grant_ref_t ref);
123 /*
124 * Grant a domain to access a range of bytes within the page referred by
125 * an available grant entry. Ref parameter is reference of a grant entry
126 * which will be sub-page accessed, domid is id of grantee domain, frame
127 * is frame address of subpage grant, flags is grant type and flag
128 * information, page_off is offset of the range of bytes, and length is
129 * length of bytes to be accessed.
130 */
131 void (*update_subpage_entry)(grant_ref_t ref, domid_t domid,
132 unsigned long frame, int flags,
133 unsigned page_off, unsigned length);
134 /*
135 * Redirect an available grant entry on domain A to another grant
136 * reference of domain B, then allow domain C to use grant reference
137 * of domain B transitively. Ref parameter is an available grant entry
138 * reference on domain A, domid is id of domain C which accesses grant
139 * entry transitively, flags is grant type and flag information,
140 * trans_domid is id of domain B whose grant entry is finally accessed
141 * transitively, trans_gref is grant entry transitive reference of
142 * domain B.
143 */
144 void (*update_trans_entry)(grant_ref_t ref, domid_t domid, int flags,
145 domid_t trans_domid, grant_ref_t trans_gref);
146};
147
148static struct gnttab_ops *gnttab_interface;
149
150/*This reflects status of grant entries, so act as a global value*/
151static grant_status_t *grstatus;
152
153static int grant_table_version;
68 154
69static struct gnttab_free_callback *gnttab_free_callback_list; 155static struct gnttab_free_callback *gnttab_free_callback_list;
70 156
71static int gnttab_expand(unsigned int req_entries); 157static int gnttab_expand(unsigned int req_entries);
72 158
73#define RPP (PAGE_SIZE / sizeof(grant_ref_t)) 159#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
160#define SPP (PAGE_SIZE / sizeof(grant_status_t))
74 161
75static inline grant_ref_t *__gnttab_entry(grant_ref_t entry) 162static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
76{ 163{
@@ -142,23 +229,33 @@ static void put_free_entry(grant_ref_t ref)
142 spin_unlock_irqrestore(&gnttab_list_lock, flags); 229 spin_unlock_irqrestore(&gnttab_list_lock, flags);
143} 230}
144 231
145static void update_grant_entry(grant_ref_t ref, domid_t domid, 232/*
146 unsigned long frame, unsigned flags) 233 * Following applies to gnttab_update_entry_v1 and gnttab_update_entry_v2.
234 * Introducing a valid entry into the grant table:
235 * 1. Write ent->domid.
236 * 2. Write ent->frame:
237 * GTF_permit_access: Frame to which access is permitted.
238 * GTF_accept_transfer: Pseudo-phys frame slot being filled by new
239 * frame, or zero if none.
240 * 3. Write memory barrier (WMB).
241 * 4. Write ent->flags, inc. valid type.
242 */
243static void gnttab_update_entry_v1(grant_ref_t ref, domid_t domid,
244 unsigned long frame, unsigned flags)
245{
246 gnttab_shared.v1[ref].domid = domid;
247 gnttab_shared.v1[ref].frame = frame;
248 wmb();
249 gnttab_shared.v1[ref].flags = flags;
250}
251
252static void gnttab_update_entry_v2(grant_ref_t ref, domid_t domid,
253 unsigned long frame, unsigned flags)
147{ 254{
148 /* 255 gnttab_shared.v2[ref].hdr.domid = domid;
149 * Introducing a valid entry into the grant table: 256 gnttab_shared.v2[ref].full_page.frame = frame;
150 * 1. Write ent->domid.
151 * 2. Write ent->frame:
152 * GTF_permit_access: Frame to which access is permitted.
153 * GTF_accept_transfer: Pseudo-phys frame slot being filled by new
154 * frame, or zero if none.
155 * 3. Write memory barrier (WMB).
156 * 4. Write ent->flags, inc. valid type.
157 */
158 shared[ref].frame = frame;
159 shared[ref].domid = domid;
160 wmb(); 257 wmb();
161 shared[ref].flags = flags; 258 gnttab_shared.v2[ref].hdr.flags = GTF_permit_access | flags;
162} 259}
163 260
164/* 261/*
@@ -167,7 +264,7 @@ static void update_grant_entry(grant_ref_t ref, domid_t domid,
167void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, 264void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
168 unsigned long frame, int readonly) 265 unsigned long frame, int readonly)
169{ 266{
170 update_grant_entry(ref, domid, frame, 267 gnttab_interface->update_entry(ref, domid, frame,
171 GTF_permit_access | (readonly ? GTF_readonly : 0)); 268 GTF_permit_access | (readonly ? GTF_readonly : 0));
172} 269}
173EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref); 270EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
@@ -187,31 +284,184 @@ int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
187} 284}
188EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access); 285EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
189 286
190int gnttab_query_foreign_access(grant_ref_t ref) 287void gnttab_update_subpage_entry_v2(grant_ref_t ref, domid_t domid,
288 unsigned long frame, int flags,
289 unsigned page_off,
290 unsigned length)
291{
292 gnttab_shared.v2[ref].sub_page.frame = frame;
293 gnttab_shared.v2[ref].sub_page.page_off = page_off;
294 gnttab_shared.v2[ref].sub_page.length = length;
295 gnttab_shared.v2[ref].hdr.domid = domid;
296 wmb();
297 gnttab_shared.v2[ref].hdr.flags =
298 GTF_permit_access | GTF_sub_page | flags;
299}
300
301int gnttab_grant_foreign_access_subpage_ref(grant_ref_t ref, domid_t domid,
302 unsigned long frame, int flags,
303 unsigned page_off,
304 unsigned length)
191{ 305{
192 u16 nflags; 306 if (flags & (GTF_accept_transfer | GTF_reading |
307 GTF_writing | GTF_transitive))
308 return -EPERM;
193 309
194 nflags = shared[ref].flags; 310 if (gnttab_interface->update_subpage_entry == NULL)
311 return -ENOSYS;
195 312
196 return nflags & (GTF_reading|GTF_writing); 313 gnttab_interface->update_subpage_entry(ref, domid, frame, flags,
314 page_off, length);
315
316 return 0;
317}
318EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_subpage_ref);
319
320int gnttab_grant_foreign_access_subpage(domid_t domid, unsigned long frame,
321 int flags, unsigned page_off,
322 unsigned length)
323{
324 int ref, rc;
325
326 ref = get_free_entries(1);
327 if (unlikely(ref < 0))
328 return -ENOSPC;
329
330 rc = gnttab_grant_foreign_access_subpage_ref(ref, domid, frame, flags,
331 page_off, length);
332 if (rc < 0) {
333 put_free_entry(ref);
334 return rc;
335 }
336
337 return ref;
338}
339EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_subpage);
340
341bool gnttab_subpage_grants_available(void)
342{
343 return gnttab_interface->update_subpage_entry != NULL;
344}
345EXPORT_SYMBOL_GPL(gnttab_subpage_grants_available);
346
347void gnttab_update_trans_entry_v2(grant_ref_t ref, domid_t domid,
348 int flags, domid_t trans_domid,
349 grant_ref_t trans_gref)
350{
351 gnttab_shared.v2[ref].transitive.trans_domid = trans_domid;
352 gnttab_shared.v2[ref].transitive.gref = trans_gref;
353 gnttab_shared.v2[ref].hdr.domid = domid;
354 wmb();
355 gnttab_shared.v2[ref].hdr.flags =
356 GTF_permit_access | GTF_transitive | flags;
357}
358
359int gnttab_grant_foreign_access_trans_ref(grant_ref_t ref, domid_t domid,
360 int flags, domid_t trans_domid,
361 grant_ref_t trans_gref)
362{
363 if (flags & (GTF_accept_transfer | GTF_reading |
364 GTF_writing | GTF_sub_page))
365 return -EPERM;
366
367 if (gnttab_interface->update_trans_entry == NULL)
368 return -ENOSYS;
369
370 gnttab_interface->update_trans_entry(ref, domid, flags, trans_domid,
371 trans_gref);
372
373 return 0;
374}
375EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_trans_ref);
376
377int gnttab_grant_foreign_access_trans(domid_t domid, int flags,
378 domid_t trans_domid,
379 grant_ref_t trans_gref)
380{
381 int ref, rc;
382
383 ref = get_free_entries(1);
384 if (unlikely(ref < 0))
385 return -ENOSPC;
386
387 rc = gnttab_grant_foreign_access_trans_ref(ref, domid, flags,
388 trans_domid, trans_gref);
389 if (rc < 0) {
390 put_free_entry(ref);
391 return rc;
392 }
393
394 return ref;
395}
396EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_trans);
397
398bool gnttab_trans_grants_available(void)
399{
400 return gnttab_interface->update_trans_entry != NULL;
401}
402EXPORT_SYMBOL_GPL(gnttab_trans_grants_available);
403
404static int gnttab_query_foreign_access_v1(grant_ref_t ref)
405{
406 return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing);
407}
408
409static int gnttab_query_foreign_access_v2(grant_ref_t ref)
410{
411 return grstatus[ref] & (GTF_reading|GTF_writing);
412}
413
414int gnttab_query_foreign_access(grant_ref_t ref)
415{
416 return gnttab_interface->query_foreign_access(ref);
197} 417}
198EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); 418EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
199 419
200int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) 420static int gnttab_end_foreign_access_ref_v1(grant_ref_t ref, int readonly)
201{ 421{
202 u16 flags, nflags; 422 u16 flags, nflags;
423 u16 *pflags;
203 424
204 nflags = shared[ref].flags; 425 pflags = &gnttab_shared.v1[ref].flags;
426 nflags = *pflags;
205 do { 427 do {
206 flags = nflags; 428 flags = nflags;
207 if (flags & (GTF_reading|GTF_writing)) { 429 if (flags & (GTF_reading|GTF_writing)) {
208 printk(KERN_ALERT "WARNING: g.e. still in use!\n"); 430 printk(KERN_ALERT "WARNING: g.e. still in use!\n");
209 return 0; 431 return 0;
210 } 432 }
211 } while ((nflags = sync_cmpxchg(&shared[ref].flags, flags, 0)) != flags); 433 } while ((nflags = sync_cmpxchg(pflags, flags, 0)) != flags);
434
435 return 1;
436}
437
438static int gnttab_end_foreign_access_ref_v2(grant_ref_t ref, int readonly)
439{
440 gnttab_shared.v2[ref].hdr.flags = 0;
441 mb();
442 if (grstatus[ref] & (GTF_reading|GTF_writing)) {
443 return 0;
444 } else {
445 /* The read of grstatus needs to have acquire
446 semantics. On x86, reads already have
447 that, and we just need to protect against
448 compiler reorderings. On other
449 architectures we may need a full
450 barrier. */
451#ifdef CONFIG_X86
452 barrier();
453#else
454 mb();
455#endif
456 }
212 457
213 return 1; 458 return 1;
214} 459}
460
461int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
462{
463 return gnttab_interface->end_foreign_access_ref(ref, readonly);
464}
215EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref); 465EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
216 466
217void gnttab_end_foreign_access(grant_ref_t ref, int readonly, 467void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
@@ -246,37 +496,76 @@ EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
246void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, 496void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
247 unsigned long pfn) 497 unsigned long pfn)
248{ 498{
249 update_grant_entry(ref, domid, pfn, GTF_accept_transfer); 499 gnttab_interface->update_entry(ref, domid, pfn, GTF_accept_transfer);
250} 500}
251EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref); 501EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
252 502
253unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref) 503static unsigned long gnttab_end_foreign_transfer_ref_v1(grant_ref_t ref)
254{ 504{
255 unsigned long frame; 505 unsigned long frame;
256 u16 flags; 506 u16 flags;
507 u16 *pflags;
508
509 pflags = &gnttab_shared.v1[ref].flags;
257 510
258 /* 511 /*
259 * If a transfer is not even yet started, try to reclaim the grant 512 * If a transfer is not even yet started, try to reclaim the grant
260 * reference and return failure (== 0). 513 * reference and return failure (== 0).
261 */ 514 */
262 while (!((flags = shared[ref].flags) & GTF_transfer_committed)) { 515 while (!((flags = *pflags) & GTF_transfer_committed)) {
263 if (sync_cmpxchg(&shared[ref].flags, flags, 0) == flags) 516 if (sync_cmpxchg(pflags, flags, 0) == flags)
264 return 0; 517 return 0;
265 cpu_relax(); 518 cpu_relax();
266 } 519 }
267 520
268 /* If a transfer is in progress then wait until it is completed. */ 521 /* If a transfer is in progress then wait until it is completed. */
269 while (!(flags & GTF_transfer_completed)) { 522 while (!(flags & GTF_transfer_completed)) {
270 flags = shared[ref].flags; 523 flags = *pflags;
271 cpu_relax(); 524 cpu_relax();
272 } 525 }
273 526
274 rmb(); /* Read the frame number /after/ reading completion status. */ 527 rmb(); /* Read the frame number /after/ reading completion status. */
275 frame = shared[ref].frame; 528 frame = gnttab_shared.v1[ref].frame;
529 BUG_ON(frame == 0);
530
531 return frame;
532}
533
534static unsigned long gnttab_end_foreign_transfer_ref_v2(grant_ref_t ref)
535{
536 unsigned long frame;
537 u16 flags;
538 u16 *pflags;
539
540 pflags = &gnttab_shared.v2[ref].hdr.flags;
541
542 /*
543 * If a transfer is not even yet started, try to reclaim the grant
544 * reference and return failure (== 0).
545 */
546 while (!((flags = *pflags) & GTF_transfer_committed)) {
547 if (sync_cmpxchg(pflags, flags, 0) == flags)
548 return 0;
549 cpu_relax();
550 }
551
552 /* If a transfer is in progress then wait until it is completed. */
553 while (!(flags & GTF_transfer_completed)) {
554 flags = *pflags;
555 cpu_relax();
556 }
557
558 rmb(); /* Read the frame number /after/ reading completion status. */
559 frame = gnttab_shared.v2[ref].full_page.frame;
276 BUG_ON(frame == 0); 560 BUG_ON(frame == 0);
277 561
278 return frame; 562 return frame;
279} 563}
564
565unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
566{
567 return gnttab_interface->end_foreign_transfer_ref(ref);
568}
280EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref); 569EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
281 570
282unsigned long gnttab_end_foreign_transfer(grant_ref_t ref) 571unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
@@ -448,8 +737,8 @@ unsigned int gnttab_max_grant_frames(void)
448EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); 737EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);
449 738
450int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, 739int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
451 struct gnttab_map_grant_ref *kmap_ops, 740 struct gnttab_map_grant_ref *kmap_ops,
452 struct page **pages, unsigned int count) 741 struct page **pages, unsigned int count)
453{ 742{
454 int i, ret; 743 int i, ret;
455 pte_t *pte; 744 pte_t *pte;
@@ -499,7 +788,7 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
499EXPORT_SYMBOL_GPL(gnttab_map_refs); 788EXPORT_SYMBOL_GPL(gnttab_map_refs);
500 789
501int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, 790int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
502 struct page **pages, unsigned int count) 791 struct page **pages, unsigned int count)
503{ 792{
504 int i, ret; 793 int i, ret;
505 794
@@ -520,6 +809,77 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
520} 809}
521EXPORT_SYMBOL_GPL(gnttab_unmap_refs); 810EXPORT_SYMBOL_GPL(gnttab_unmap_refs);
522 811
812static unsigned nr_status_frames(unsigned nr_grant_frames)
813{
814 return (nr_grant_frames * GREFS_PER_GRANT_FRAME + SPP - 1) / SPP;
815}
816
817static int gnttab_map_frames_v1(unsigned long *frames, unsigned int nr_gframes)
818{
819 int rc;
820
821 rc = arch_gnttab_map_shared(frames, nr_gframes,
822 gnttab_max_grant_frames(),
823 &gnttab_shared.addr);
824 BUG_ON(rc);
825
826 return 0;
827}
828
829static void gnttab_unmap_frames_v1(void)
830{
831 arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames);
832}
833
834static int gnttab_map_frames_v2(unsigned long *frames, unsigned int nr_gframes)
835{
836 uint64_t *sframes;
837 unsigned int nr_sframes;
838 struct gnttab_get_status_frames getframes;
839 int rc;
840
841 nr_sframes = nr_status_frames(nr_gframes);
842
843 /* No need for kzalloc as it is initialized in following hypercall
844 * GNTTABOP_get_status_frames.
845 */
846 sframes = kmalloc(nr_sframes * sizeof(uint64_t), GFP_ATOMIC);
847 if (!sframes)
848 return -ENOMEM;
849
850 getframes.dom = DOMID_SELF;
851 getframes.nr_frames = nr_sframes;
852 set_xen_guest_handle(getframes.frame_list, sframes);
853
854 rc = HYPERVISOR_grant_table_op(GNTTABOP_get_status_frames,
855 &getframes, 1);
856 if (rc == -ENOSYS) {
857 kfree(sframes);
858 return -ENOSYS;
859 }
860
861 BUG_ON(rc || getframes.status);
862
863 rc = arch_gnttab_map_status(sframes, nr_sframes,
864 nr_status_frames(gnttab_max_grant_frames()),
865 &grstatus);
866 BUG_ON(rc);
867 kfree(sframes);
868
869 rc = arch_gnttab_map_shared(frames, nr_gframes,
870 gnttab_max_grant_frames(),
871 &gnttab_shared.addr);
872 BUG_ON(rc);
873
874 return 0;
875}
876
877static void gnttab_unmap_frames_v2(void)
878{
879 arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames);
880 arch_gnttab_unmap(grstatus, nr_status_frames(nr_grant_frames));
881}
882
523static int gnttab_map(unsigned int start_idx, unsigned int end_idx) 883static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
524{ 884{
525 struct gnttab_setup_table setup; 885 struct gnttab_setup_table setup;
@@ -551,6 +911,9 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
551 return rc; 911 return rc;
552 } 912 }
553 913
914 /* No need for kzalloc as it is initialized in following hypercall
915 * GNTTABOP_setup_table.
916 */
554 frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); 917 frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
555 if (!frames) 918 if (!frames)
556 return -ENOMEM; 919 return -ENOMEM;
@@ -567,19 +930,65 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
567 930
568 BUG_ON(rc || setup.status); 931 BUG_ON(rc || setup.status);
569 932
570 rc = arch_gnttab_map_shared(frames, nr_gframes, gnttab_max_grant_frames(), 933 rc = gnttab_interface->map_frames(frames, nr_gframes);
571 &shared);
572 BUG_ON(rc);
573 934
574 kfree(frames); 935 kfree(frames);
575 936
576 return 0; 937 return rc;
938}
939
940static struct gnttab_ops gnttab_v1_ops = {
941 .map_frames = gnttab_map_frames_v1,
942 .unmap_frames = gnttab_unmap_frames_v1,
943 .update_entry = gnttab_update_entry_v1,
944 .end_foreign_access_ref = gnttab_end_foreign_access_ref_v1,
945 .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v1,
946 .query_foreign_access = gnttab_query_foreign_access_v1,
947};
948
949static struct gnttab_ops gnttab_v2_ops = {
950 .map_frames = gnttab_map_frames_v2,
951 .unmap_frames = gnttab_unmap_frames_v2,
952 .update_entry = gnttab_update_entry_v2,
953 .end_foreign_access_ref = gnttab_end_foreign_access_ref_v2,
954 .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v2,
955 .query_foreign_access = gnttab_query_foreign_access_v2,
956 .update_subpage_entry = gnttab_update_subpage_entry_v2,
957 .update_trans_entry = gnttab_update_trans_entry_v2,
958};
959
960static void gnttab_request_version(void)
961{
962 int rc;
963 struct gnttab_set_version gsv;
964
965 gsv.version = 2;
966 rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1);
967 if (rc == 0) {
968 grant_table_version = 2;
969 gnttab_interface = &gnttab_v2_ops;
970 } else if (grant_table_version == 2) {
971 /*
972 * If we've already used version 2 features,
973 * but then suddenly discover that they're not
974 * available (e.g. migrating to an older
975 * version of Xen), almost unbounded badness
976 * can happen.
977 */
978 panic("we need grant tables version 2, but only version 1 is available");
979 } else {
980 grant_table_version = 1;
981 gnttab_interface = &gnttab_v1_ops;
982 }
983 printk(KERN_INFO "Grant tables using version %d layout.\n",
984 grant_table_version);
577} 985}
578 986
579int gnttab_resume(void) 987int gnttab_resume(void)
580{ 988{
581 unsigned int max_nr_gframes; 989 unsigned int max_nr_gframes;
582 990
991 gnttab_request_version();
583 max_nr_gframes = gnttab_max_grant_frames(); 992 max_nr_gframes = gnttab_max_grant_frames();
584 if (max_nr_gframes < nr_grant_frames) 993 if (max_nr_gframes < nr_grant_frames)
585 return -ENOSYS; 994 return -ENOSYS;
@@ -587,9 +996,10 @@ int gnttab_resume(void)
587 if (xen_pv_domain()) 996 if (xen_pv_domain())
588 return gnttab_map(0, nr_grant_frames - 1); 997 return gnttab_map(0, nr_grant_frames - 1);
589 998
590 if (!shared) { 999 if (gnttab_shared.addr == NULL) {
591 shared = ioremap(xen_hvm_resume_frames, PAGE_SIZE * max_nr_gframes); 1000 gnttab_shared.addr = ioremap(xen_hvm_resume_frames,
592 if (shared == NULL) { 1001 PAGE_SIZE * max_nr_gframes);
1002 if (gnttab_shared.addr == NULL) {
593 printk(KERN_WARNING 1003 printk(KERN_WARNING
594 "Failed to ioremap gnttab share frames!"); 1004 "Failed to ioremap gnttab share frames!");
595 return -ENOMEM; 1005 return -ENOMEM;
@@ -603,7 +1013,7 @@ int gnttab_resume(void)
603 1013
604int gnttab_suspend(void) 1014int gnttab_suspend(void)
605{ 1015{
606 arch_gnttab_unmap_shared(shared, nr_grant_frames); 1016 gnttab_interface->unmap_frames();
607 return 0; 1017 return 0;
608} 1018}
609 1019
diff --git a/drivers/xen/xenfs/privcmd.c b/drivers/xen/privcmd.c
index dbd3b16fd131..ccee0f16bcf8 100644
--- a/drivers/xen/xenfs/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -7,6 +7,7 @@
7 */ 7 */
8 8
9#include <linux/kernel.h> 9#include <linux/kernel.h>
10#include <linux/module.h>
10#include <linux/sched.h> 11#include <linux/sched.h>
11#include <linux/slab.h> 12#include <linux/slab.h>
12#include <linux/string.h> 13#include <linux/string.h>
@@ -18,6 +19,7 @@
18#include <linux/highmem.h> 19#include <linux/highmem.h>
19#include <linux/pagemap.h> 20#include <linux/pagemap.h>
20#include <linux/seq_file.h> 21#include <linux/seq_file.h>
22#include <linux/miscdevice.h>
21 23
22#include <asm/pgalloc.h> 24#include <asm/pgalloc.h>
23#include <asm/pgtable.h> 25#include <asm/pgtable.h>
@@ -32,6 +34,10 @@
32#include <xen/page.h> 34#include <xen/page.h>
33#include <xen/xen-ops.h> 35#include <xen/xen-ops.h>
34 36
37#include "privcmd.h"
38
39MODULE_LICENSE("GPL");
40
35#ifndef HAVE_ARCH_PRIVCMD_MMAP 41#ifndef HAVE_ARCH_PRIVCMD_MMAP
36static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma); 42static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
37#endif 43#endif
@@ -359,7 +365,6 @@ static long privcmd_ioctl(struct file *file,
359 return ret; 365 return ret;
360} 366}
361 367
362#ifndef HAVE_ARCH_PRIVCMD_MMAP
363static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 368static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
364{ 369{
365 printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n", 370 printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n",
@@ -392,9 +397,39 @@ static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
392{ 397{
393 return (xchg(&vma->vm_private_data, (void *)1) == NULL); 398 return (xchg(&vma->vm_private_data, (void *)1) == NULL);
394} 399}
395#endif
396 400
397const struct file_operations privcmd_file_ops = { 401const struct file_operations xen_privcmd_fops = {
402 .owner = THIS_MODULE,
398 .unlocked_ioctl = privcmd_ioctl, 403 .unlocked_ioctl = privcmd_ioctl,
399 .mmap = privcmd_mmap, 404 .mmap = privcmd_mmap,
400}; 405};
406EXPORT_SYMBOL_GPL(xen_privcmd_fops);
407
408static struct miscdevice privcmd_dev = {
409 .minor = MISC_DYNAMIC_MINOR,
410 .name = "xen/privcmd",
411 .fops = &xen_privcmd_fops,
412};
413
414static int __init privcmd_init(void)
415{
416 int err;
417
418 if (!xen_domain())
419 return -ENODEV;
420
421 err = misc_register(&privcmd_dev);
422 if (err != 0) {
423 printk(KERN_ERR "Could not register Xen privcmd device\n");
424 return err;
425 }
426 return 0;
427}
428
429static void __exit privcmd_exit(void)
430{
431 misc_deregister(&privcmd_dev);
432}
433
434module_init(privcmd_init);
435module_exit(privcmd_exit);
diff --git a/drivers/xen/privcmd.h b/drivers/xen/privcmd.h
new file mode 100644
index 000000000000..14facaeed36f
--- /dev/null
+++ b/drivers/xen/privcmd.h
@@ -0,0 +1,3 @@
1#include <linux/fs.h>
2
3extern const struct file_operations xen_privcmd_fops;
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 @@
1obj-y += xenbus.o 1obj-y += xenbus.o
2obj-y += xenbus_dev_frontend.o
2 3
3xenbus-objs = 4xenbus-objs =
4xenbus-objs += xenbus_client.o 5xenbus-objs += xenbus_client.o
@@ -9,4 +10,5 @@ xenbus-objs += xenbus_probe.o
9xenbus-be-objs-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o 10xenbus-be-objs-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o
10xenbus-objs += $(xenbus-be-objs-y) 11xenbus-objs += $(xenbus-be-objs-y)
11 12
13obj-$(CONFIG_XEN_BACKEND) += xenbus_dev_backend.o
12obj-$(CONFIG_XEN_XENBUS_FRONTEND) += xenbus_probe_frontend.o 14obj-$(CONFIG_XEN_XENBUS_FRONTEND) += xenbus_probe_frontend.o
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
34int xs_init(void); 36int xs_init(void);
35int xb_init_comms(void); 37int xb_init_comms(void);
36 38
@@ -43,4 +45,6 @@ int xs_input_avail(void);
43extern struct xenstore_domain_interface *xen_store_interface; 45extern struct xenstore_domain_interface *xen_store_interface;
44extern int xen_store_evtchn; 46extern int xen_store_evtchn;
45 47
48extern 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..a2092bd97693
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_dev_backend.c
@@ -0,0 +1,89 @@
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/page.h>
10#include <xen/xenbus_dev.h>
11
12#include "xenbus_comms.h"
13
14MODULE_LICENSE("GPL");
15
16static int xenbus_backend_open(struct inode *inode, struct file *filp)
17{
18 if (!capable(CAP_SYS_ADMIN))
19 return -EPERM;
20
21 return nonseekable_open(inode, filp);
22}
23
24static long xenbus_backend_ioctl(struct file *file, unsigned int cmd, unsigned long data)
25{
26 if (!capable(CAP_SYS_ADMIN))
27 return -EPERM;
28
29 switch (cmd) {
30 case IOCTL_XENBUS_BACKEND_EVTCHN:
31 if (xen_store_evtchn > 0)
32 return xen_store_evtchn;
33 return -ENODEV;
34
35 default:
36 return -ENOTTY;
37 }
38}
39
40static int xenbus_backend_mmap(struct file *file, struct vm_area_struct *vma)
41{
42 size_t size = vma->vm_end - vma->vm_start;
43
44 if (!capable(CAP_SYS_ADMIN))
45 return -EPERM;
46
47 if ((size > PAGE_SIZE) || (vma->vm_pgoff != 0))
48 return -EINVAL;
49
50 if (remap_pfn_range(vma, vma->vm_start,
51 virt_to_pfn(xen_store_interface),
52 size, vma->vm_page_prot))
53 return -EAGAIN;
54
55 return 0;
56}
57
58const struct file_operations xenbus_backend_fops = {
59 .open = xenbus_backend_open,
60 .mmap = xenbus_backend_mmap,
61 .unlocked_ioctl = xenbus_backend_ioctl,
62};
63
64static struct miscdevice xenbus_backend_dev = {
65 .minor = MISC_DYNAMIC_MINOR,
66 .name = "xen/xenbus_backend",
67 .fops = &xenbus_backend_fops,
68};
69
70static int __init xenbus_backend_init(void)
71{
72 int err;
73
74 if (!xen_initial_domain())
75 return -ENODEV;
76
77 err = misc_register(&xenbus_backend_dev);
78 if (err)
79 printk(KERN_ERR "Could not register xenbus backend device\n");
80 return err;
81}
82
83static void __exit xenbus_backend_exit(void)
84{
85 misc_deregister(&xenbus_backend_dev);
86}
87
88module_init(xenbus_backend_init);
89module_exit(xenbus_backend_exit);
diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenbus/xenbus_dev_frontend.c
index bbd000f88af7..aec01420d979 100644
--- a/drivers/xen/xenfs/xenbus.c
+++ b/drivers/xen/xenbus/xenbus_dev_frontend.c
@@ -52,13 +52,17 @@
52#include <linux/namei.h> 52#include <linux/namei.h>
53#include <linux/string.h> 53#include <linux/string.h>
54#include <linux/slab.h> 54#include <linux/slab.h>
55#include <linux/miscdevice.h>
56#include <linux/module.h>
55 57
56#include "xenfs.h" 58#include "xenbus_comms.h"
57#include "../xenbus/xenbus_comms.h"
58 59
59#include <xen/xenbus.h> 60#include <xen/xenbus.h>
61#include <xen/xen.h>
60#include <asm/xen/hypervisor.h> 62#include <asm/xen/hypervisor.h>
61 63
64MODULE_LICENSE("GPL");
65
62/* 66/*
63 * An element of a list of outstanding transactions, for which we're 67 * An element of a list of outstanding transactions, for which we're
64 * still waiting a reply. 68 * still waiting a reply.
@@ -583,7 +587,7 @@ static unsigned int xenbus_file_poll(struct file *file, poll_table *wait)
583 return 0; 587 return 0;
584} 588}
585 589
586const struct file_operations xenbus_file_ops = { 590const struct file_operations xen_xenbus_fops = {
587 .read = xenbus_file_read, 591 .read = xenbus_file_read,
588 .write = xenbus_file_write, 592 .write = xenbus_file_write,
589 .open = xenbus_file_open, 593 .open = xenbus_file_open,
@@ -591,3 +595,31 @@ const struct file_operations xenbus_file_ops = {
591 .poll = xenbus_file_poll, 595 .poll = xenbus_file_poll,
592 .llseek = no_llseek, 596 .llseek = no_llseek,
593}; 597};
598EXPORT_SYMBOL_GPL(xen_xenbus_fops);
599
600static struct miscdevice xenbus_dev = {
601 .minor = MISC_DYNAMIC_MINOR,
602 .name = "xen/xenbus",
603 .fops = &xen_xenbus_fops,
604};
605
606static 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
619static void __exit xenbus_exit(void)
620{
621 misc_deregister(&xenbus_dev);
622}
623
624module_init(xenbus_init);
625module_exit(xenbus_exit);
diff --git a/drivers/xen/xenfs/Makefile b/drivers/xen/xenfs/Makefile
index 4fde9440fe1f..b019865fcc56 100644
--- a/drivers/xen/xenfs/Makefile
+++ b/drivers/xen/xenfs/Makefile
@@ -1,4 +1,4 @@
1obj-$(CONFIG_XENFS) += xenfs.o 1obj-$(CONFIG_XENFS) += xenfs.o
2 2
3xenfs-y = super.o xenbus.o privcmd.o 3xenfs-y = super.o
4xenfs-$(CONFIG_XEN_DOM0) += xenstored.o 4xenfs-$(CONFIG_XEN_DOM0) += xenstored.o
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c
index 1aa389719846..a84b53c01436 100644
--- a/drivers/xen/xenfs/super.c
+++ b/drivers/xen/xenfs/super.c
@@ -16,6 +16,8 @@
16#include <xen/xen.h> 16#include <xen/xen.h>
17 17
18#include "xenfs.h" 18#include "xenfs.h"
19#include "../privcmd.h"
20#include "../xenbus/xenbus_comms.h"
19 21
20#include <asm/xen/hypervisor.h> 22#include <asm/xen/hypervisor.h>
21 23
@@ -82,9 +84,9 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
82{ 84{
83 static struct tree_descr xenfs_files[] = { 85 static struct tree_descr xenfs_files[] = {
84 [1] = {}, 86 [1] = {},
85 { "xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR }, 87 { "xenbus", &xen_xenbus_fops, S_IRUSR|S_IWUSR },
86 { "capabilities", &capabilities_file_ops, S_IRUGO }, 88 { "capabilities", &capabilities_file_ops, S_IRUGO },
87 { "privcmd", &privcmd_file_ops, S_IRUSR|S_IWUSR }, 89 { "privcmd", &xen_privcmd_fops, S_IRUSR|S_IWUSR },
88 {""}, 90 {""},
89 }; 91 };
90 int rc; 92 int rc;
diff --git a/drivers/xen/xenfs/xenfs.h b/drivers/xen/xenfs/xenfs.h
index b68aa6200003..6b80c7779c02 100644
--- a/drivers/xen/xenfs/xenfs.h
+++ b/drivers/xen/xenfs/xenfs.h
@@ -1,8 +1,6 @@
1#ifndef _XENFS_XENBUS_H 1#ifndef _XENFS_XENBUS_H
2#define _XENFS_XENBUS_H 2#define _XENFS_XENBUS_H
3 3
4extern const struct file_operations xenbus_file_ops;
5extern const struct file_operations privcmd_file_ops;
6extern const struct file_operations xsd_kva_file_ops; 4extern const struct file_operations xsd_kva_file_ops;
7extern const struct file_operations xsd_port_file_ops; 5extern const struct file_operations xsd_port_file_ops;
8 6