diff options
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/Kconfig | 7 | ||||
-rw-r--r-- | drivers/xen/Makefile | 2 | ||||
-rw-r--r-- | drivers/xen/events.c | 77 | ||||
-rw-r--r-- | drivers/xen/evtchn.c | 2 | ||||
-rw-r--r-- | drivers/xen/gntalloc.c | 120 | ||||
-rw-r--r-- | drivers/xen/gntdev.c | 31 | ||||
-rw-r--r-- | drivers/xen/grant-table.c | 496 | ||||
-rw-r--r-- | drivers/xen/privcmd.c (renamed from drivers/xen/xenfs/privcmd.c) | 41 | ||||
-rw-r--r-- | drivers/xen/privcmd.h | 3 | ||||
-rw-r--r-- | drivers/xen/xenbus/Makefile | 2 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_comms.h | 4 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_dev_backend.c | 89 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_dev_frontend.c (renamed from drivers/xen/xenfs/xenbus.c) | 38 | ||||
-rw-r--r-- | drivers/xen/xenfs/Makefile | 2 | ||||
-rw-r--r-- | drivers/xen/xenfs/super.c | 6 | ||||
-rw-r--r-- | drivers/xen/xenfs/xenfs.h | 2 |
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 | ||
87 | config XENFS | 87 | config 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 | |||
176 | config XEN_PRIVCMD | ||
177 | tristate | ||
178 | depends on XEN | ||
179 | default m | ||
180 | |||
174 | endmenu | 181 | endmenu |
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 | |||
19 | obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o | 19 | obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o |
20 | obj-$(CONFIG_XEN_DOM0) += pci.o | 20 | obj-$(CONFIG_XEN_DOM0) += pci.o |
21 | obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/ | 21 | obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/ |
22 | obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o | ||
22 | 23 | ||
23 | xen-evtchn-y := evtchn.o | 24 | xen-evtchn-y := evtchn.o |
24 | xen-gntdev-y := gntdev.o | 25 | xen-gntdev-y := gntdev.o |
25 | xen-gntalloc-y := gntalloc.o | 26 | xen-gntalloc-y := gntalloc.o |
27 | xen-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 | */ |
88 | struct irq_info { | 88 | struct 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 | } |
1066 | EXPORT_SYMBOL_GPL(unbind_from_irqhandler); | 1078 | EXPORT_SYMBOL_GPL(unbind_from_irqhandler); |
1067 | 1079 | ||
1080 | int 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 | } | ||
1099 | EXPORT_SYMBOL_GPL(evtchn_make_refcounted); | ||
1100 | |||
1101 | int 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 | } | ||
1132 | EXPORT_SYMBOL_GPL(evtchn_get); | ||
1133 | |||
1134 | void 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 | } | ||
1141 | EXPORT_SYMBOL_GPL(evtchn_put); | ||
1142 | |||
1068 | void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector) | 1143 | void 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 | ||
76 | static LIST_HEAD(gref_list); | 76 | static LIST_HEAD(gref_list); |
77 | static DEFINE_SPINLOCK(gref_lock); | 77 | static DEFINE_MUTEX(gref_mutex); |
78 | static int gref_size; | 78 | static int gref_size; |
79 | 79 | ||
80 | struct notify_info { | 80 | struct notify_info { |
@@ -99,6 +99,12 @@ struct gntalloc_file_private_data { | |||
99 | uint64_t index; | 99 | uint64_t index; |
100 | }; | 100 | }; |
101 | 101 | ||
102 | struct gntalloc_vma_private_data { | ||
103 | struct gntalloc_gref *gref; | ||
104 | int users; | ||
105 | int count; | ||
106 | }; | ||
107 | |||
102 | static void __del_gref(struct gntalloc_gref *gref); | 108 | static void __del_gref(struct gntalloc_gref *gref); |
103 | 109 | ||
104 | static void do_cleanup(void) | 110 | static 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 | ||
153 | undo: | 159 | undo: |
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); |
367 | dealloc_grant_out: | 377 | dealloc_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 | ||
430 | static void gntalloc_vma_open(struct vm_area_struct *vma) | 458 | static 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 | ||
441 | static void gntalloc_vma_close(struct vm_area_struct *vma) | 470 | static 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 | ||
454 | static struct vm_operations_struct gntalloc_vmops = { | 496 | static struct vm_operations_struct gntalloc_vmops = { |
@@ -459,19 +501,25 @@ static struct vm_operations_struct gntalloc_vmops = { | |||
459 | static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma) | 501 | static 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 | ||
501 | out_unlock: | 553 | out_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 | ||
58 | static grant_ref_t **gnttab_list; | 61 | static grant_ref_t **gnttab_list; |
59 | static unsigned int nr_grant_frames; | 62 | static unsigned int nr_grant_frames; |
@@ -64,13 +67,97 @@ static DEFINE_SPINLOCK(gnttab_list_lock); | |||
64 | unsigned long xen_hvm_resume_frames; | 67 | unsigned long xen_hvm_resume_frames; |
65 | EXPORT_SYMBOL_GPL(xen_hvm_resume_frames); | 68 | EXPORT_SYMBOL_GPL(xen_hvm_resume_frames); |
66 | 69 | ||
67 | static struct grant_entry *shared; | 70 | static 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*/ | ||
77 | struct 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 | |||
148 | static struct gnttab_ops *gnttab_interface; | ||
149 | |||
150 | /*This reflects status of grant entries, so act as a global value*/ | ||
151 | static grant_status_t *grstatus; | ||
152 | |||
153 | static int grant_table_version; | ||
68 | 154 | ||
69 | static struct gnttab_free_callback *gnttab_free_callback_list; | 155 | static struct gnttab_free_callback *gnttab_free_callback_list; |
70 | 156 | ||
71 | static int gnttab_expand(unsigned int req_entries); | 157 | static 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 | ||
75 | static inline grant_ref_t *__gnttab_entry(grant_ref_t entry) | 162 | static 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 | ||
145 | static 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 | */ | ||
243 | static 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 | |||
252 | static 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, | |||
167 | void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, | 264 | void 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 | } |
173 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref); | 270 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref); |
@@ -187,31 +284,184 @@ int gnttab_grant_foreign_access(domid_t domid, unsigned long frame, | |||
187 | } | 284 | } |
188 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access); | 285 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access); |
189 | 286 | ||
190 | int gnttab_query_foreign_access(grant_ref_t ref) | 287 | void 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 | |||
301 | int 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 | } | ||
318 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_subpage_ref); | ||
319 | |||
320 | int 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 | } | ||
339 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_subpage); | ||
340 | |||
341 | bool gnttab_subpage_grants_available(void) | ||
342 | { | ||
343 | return gnttab_interface->update_subpage_entry != NULL; | ||
344 | } | ||
345 | EXPORT_SYMBOL_GPL(gnttab_subpage_grants_available); | ||
346 | |||
347 | void 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 | |||
359 | int 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 | } | ||
375 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_trans_ref); | ||
376 | |||
377 | int 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 | } | ||
396 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_trans); | ||
397 | |||
398 | bool gnttab_trans_grants_available(void) | ||
399 | { | ||
400 | return gnttab_interface->update_trans_entry != NULL; | ||
401 | } | ||
402 | EXPORT_SYMBOL_GPL(gnttab_trans_grants_available); | ||
403 | |||
404 | static int gnttab_query_foreign_access_v1(grant_ref_t ref) | ||
405 | { | ||
406 | return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing); | ||
407 | } | ||
408 | |||
409 | static int gnttab_query_foreign_access_v2(grant_ref_t ref) | ||
410 | { | ||
411 | return grstatus[ref] & (GTF_reading|GTF_writing); | ||
412 | } | ||
413 | |||
414 | int gnttab_query_foreign_access(grant_ref_t ref) | ||
415 | { | ||
416 | return gnttab_interface->query_foreign_access(ref); | ||
197 | } | 417 | } |
198 | EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); | 418 | EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); |
199 | 419 | ||
200 | int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) | 420 | static 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 | |||
438 | static 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 | |||
461 | int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) | ||
462 | { | ||
463 | return gnttab_interface->end_foreign_access_ref(ref, readonly); | ||
464 | } | ||
215 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref); | 465 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref); |
216 | 466 | ||
217 | void gnttab_end_foreign_access(grant_ref_t ref, int readonly, | 467 | void gnttab_end_foreign_access(grant_ref_t ref, int readonly, |
@@ -246,37 +496,76 @@ EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer); | |||
246 | void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, | 496 | void 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 | } |
251 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref); | 501 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref); |
252 | 502 | ||
253 | unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref) | 503 | static 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 | |||
534 | static 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 | |||
565 | unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref) | ||
566 | { | ||
567 | return gnttab_interface->end_foreign_transfer_ref(ref); | ||
568 | } | ||
280 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref); | 569 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref); |
281 | 570 | ||
282 | unsigned long gnttab_end_foreign_transfer(grant_ref_t ref) | 571 | unsigned long gnttab_end_foreign_transfer(grant_ref_t ref) |
@@ -448,8 +737,8 @@ unsigned int gnttab_max_grant_frames(void) | |||
448 | EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); | 737 | EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); |
449 | 738 | ||
450 | int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, | 739 | int 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, | |||
499 | EXPORT_SYMBOL_GPL(gnttab_map_refs); | 788 | EXPORT_SYMBOL_GPL(gnttab_map_refs); |
500 | 789 | ||
501 | int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, | 790 | int 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 | } |
521 | EXPORT_SYMBOL_GPL(gnttab_unmap_refs); | 810 | EXPORT_SYMBOL_GPL(gnttab_unmap_refs); |
522 | 811 | ||
812 | static unsigned nr_status_frames(unsigned nr_grant_frames) | ||
813 | { | ||
814 | return (nr_grant_frames * GREFS_PER_GRANT_FRAME + SPP - 1) / SPP; | ||
815 | } | ||
816 | |||
817 | static 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 | |||
829 | static void gnttab_unmap_frames_v1(void) | ||
830 | { | ||
831 | arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames); | ||
832 | } | ||
833 | |||
834 | static 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 | |||
877 | static 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 | |||
523 | static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | 883 | static 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 | |||
940 | static 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 | |||
949 | static 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 | |||
960 | static 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 | ||
579 | int gnttab_resume(void) | 987 | int 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 | ||
604 | int gnttab_suspend(void) | 1014 | int 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 | |||
39 | MODULE_LICENSE("GPL"); | ||
40 | |||
35 | #ifndef HAVE_ARCH_PRIVCMD_MMAP | 41 | #ifndef HAVE_ARCH_PRIVCMD_MMAP |
36 | static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma); | 42 | static 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 | ||
363 | static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 368 | static 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 | ||
397 | const struct file_operations privcmd_file_ops = { | 401 | const 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 | }; |
406 | EXPORT_SYMBOL_GPL(xen_privcmd_fops); | ||
407 | |||
408 | static struct miscdevice privcmd_dev = { | ||
409 | .minor = MISC_DYNAMIC_MINOR, | ||
410 | .name = "xen/privcmd", | ||
411 | .fops = &xen_privcmd_fops, | ||
412 | }; | ||
413 | |||
414 | static 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 | |||
429 | static void __exit privcmd_exit(void) | ||
430 | { | ||
431 | misc_deregister(&privcmd_dev); | ||
432 | } | ||
433 | |||
434 | module_init(privcmd_init); | ||
435 | module_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 | |||
3 | extern 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 @@ | |||
1 | obj-y += xenbus.o | 1 | obj-y += xenbus.o |
2 | obj-y += xenbus_dev_frontend.o | ||
2 | 3 | ||
3 | xenbus-objs = | 4 | xenbus-objs = |
4 | xenbus-objs += xenbus_client.o | 5 | xenbus-objs += xenbus_client.o |
@@ -9,4 +10,5 @@ xenbus-objs += xenbus_probe.o | |||
9 | xenbus-be-objs-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o | 10 | xenbus-be-objs-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o |
10 | xenbus-objs += $(xenbus-be-objs-y) | 11 | xenbus-objs += $(xenbus-be-objs-y) |
11 | 12 | ||
13 | obj-$(CONFIG_XEN_BACKEND) += xenbus_dev_backend.o | ||
12 | obj-$(CONFIG_XEN_XENBUS_FRONTEND) += xenbus_probe_frontend.o | 14 | obj-$(CONFIG_XEN_XENBUS_FRONTEND) += xenbus_probe_frontend.o |
diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h index c21db7513736..6e42800fa499 100644 --- a/drivers/xen/xenbus/xenbus_comms.h +++ b/drivers/xen/xenbus/xenbus_comms.h | |||
@@ -31,6 +31,8 @@ | |||
31 | #ifndef _XENBUS_COMMS_H | 31 | #ifndef _XENBUS_COMMS_H |
32 | #define _XENBUS_COMMS_H | 32 | #define _XENBUS_COMMS_H |
33 | 33 | ||
34 | #include <linux/fs.h> | ||
35 | |||
34 | int xs_init(void); | 36 | int xs_init(void); |
35 | int xb_init_comms(void); | 37 | int xb_init_comms(void); |
36 | 38 | ||
@@ -43,4 +45,6 @@ int xs_input_avail(void); | |||
43 | extern struct xenstore_domain_interface *xen_store_interface; | 45 | extern struct xenstore_domain_interface *xen_store_interface; |
44 | extern int xen_store_evtchn; | 46 | extern int xen_store_evtchn; |
45 | 47 | ||
48 | extern const struct file_operations xen_xenbus_fops; | ||
49 | |||
46 | #endif /* _XENBUS_COMMS_H */ | 50 | #endif /* _XENBUS_COMMS_H */ |
diff --git a/drivers/xen/xenbus/xenbus_dev_backend.c b/drivers/xen/xenbus/xenbus_dev_backend.c new file mode 100644 index 000000000000..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 | |||
14 | MODULE_LICENSE("GPL"); | ||
15 | |||
16 | static 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 | |||
24 | static 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 | |||
40 | static 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 | |||
58 | const struct file_operations xenbus_backend_fops = { | ||
59 | .open = xenbus_backend_open, | ||
60 | .mmap = xenbus_backend_mmap, | ||
61 | .unlocked_ioctl = xenbus_backend_ioctl, | ||
62 | }; | ||
63 | |||
64 | static struct miscdevice xenbus_backend_dev = { | ||
65 | .minor = MISC_DYNAMIC_MINOR, | ||
66 | .name = "xen/xenbus_backend", | ||
67 | .fops = &xenbus_backend_fops, | ||
68 | }; | ||
69 | |||
70 | static 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 | |||
83 | static void __exit xenbus_backend_exit(void) | ||
84 | { | ||
85 | misc_deregister(&xenbus_backend_dev); | ||
86 | } | ||
87 | |||
88 | module_init(xenbus_backend_init); | ||
89 | module_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 | ||
64 | MODULE_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 | ||
586 | const struct file_operations xenbus_file_ops = { | 590 | const 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 | }; |
598 | EXPORT_SYMBOL_GPL(xen_xenbus_fops); | ||
599 | |||
600 | static struct miscdevice xenbus_dev = { | ||
601 | .minor = MISC_DYNAMIC_MINOR, | ||
602 | .name = "xen/xenbus", | ||
603 | .fops = &xen_xenbus_fops, | ||
604 | }; | ||
605 | |||
606 | static int __init xenbus_init(void) | ||
607 | { | ||
608 | int err; | ||
609 | |||
610 | if (!xen_domain()) | ||
611 | return -ENODEV; | ||
612 | |||
613 | err = misc_register(&xenbus_dev); | ||
614 | if (err) | ||
615 | printk(KERN_ERR "Could not register xenbus frontend device\n"); | ||
616 | return err; | ||
617 | } | ||
618 | |||
619 | static void __exit xenbus_exit(void) | ||
620 | { | ||
621 | misc_deregister(&xenbus_dev); | ||
622 | } | ||
623 | |||
624 | module_init(xenbus_init); | ||
625 | module_exit(xenbus_exit); | ||
diff --git a/drivers/xen/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 @@ | |||
1 | obj-$(CONFIG_XENFS) += xenfs.o | 1 | obj-$(CONFIG_XENFS) += xenfs.o |
2 | 2 | ||
3 | xenfs-y = super.o xenbus.o privcmd.o | 3 | xenfs-y = super.o |
4 | xenfs-$(CONFIG_XEN_DOM0) += xenstored.o | 4 | xenfs-$(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 | ||
4 | extern const struct file_operations xenbus_file_ops; | ||
5 | extern const struct file_operations privcmd_file_ops; | ||
6 | extern const struct file_operations xsd_kva_file_ops; | 4 | extern const struct file_operations xsd_kva_file_ops; |
7 | extern const struct file_operations xsd_port_file_ops; | 5 | extern const struct file_operations xsd_port_file_ops; |
8 | 6 | ||