diff options
author | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-11-30 17:07:59 -0500 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-11-30 17:07:59 -0500 |
commit | 6a7ed405114b2a53ccd99631b0636aaeabf71b3e (patch) | |
tree | f8bb0dcddc66c59843433e2283f6bea57cc8ce24 /drivers/xen | |
parent | a7be94ac8d69c037d08f0fd94b45a593f1d45176 (diff) | |
parent | f832da068b0aadb15f747f6427b6bf945f525ba4 (diff) |
Merge branch 'arm-privcmd-for-3.8' of git://xenbits.xen.org/people/ianc/linux into stable/for-linus-3.8
* 'arm-privcmd-for-3.8' of git://xenbits.xen.org/people/ianc/linux:
xen: arm: implement remap interfaces needed for privcmd mappings.
xen: correctly use xen_pfn_t in remap_domain_mfn_range.
xen: arm: enable balloon driver
xen: balloon: allow PVMMU interfaces to be compiled out
xen: privcmd: support autotranslated physmap guests.
xen: add pages parameter to xen_remap_domain_mfn_range
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/Kconfig | 3 | ||||
-rw-r--r-- | drivers/xen/Makefile | 4 | ||||
-rw-r--r-- | drivers/xen/balloon.c | 5 | ||||
-rw-r--r-- | drivers/xen/privcmd.c | 72 |
4 files changed, 78 insertions, 6 deletions
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 126d8ce591ce..cabfa97f4674 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig | |||
@@ -206,4 +206,7 @@ config XEN_MCE_LOG | |||
206 | Allow kernel fetching MCE error from Xen platform and | 206 | Allow kernel fetching MCE error from Xen platform and |
207 | converting it into Linux mcelog format for mcelog tools | 207 | converting it into Linux mcelog format for mcelog tools |
208 | 208 | ||
209 | config XEN_HAVE_PVMMU | ||
210 | bool | ||
211 | |||
209 | endmenu | 212 | endmenu |
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 3c397170f39c..3ee2b91ca4e0 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile | |||
@@ -1,8 +1,8 @@ | |||
1 | ifneq ($(CONFIG_ARM),y) | 1 | ifneq ($(CONFIG_ARM),y) |
2 | obj-y += manage.o balloon.o | 2 | obj-y += manage.o |
3 | obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o | 3 | obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o |
4 | endif | 4 | endif |
5 | obj-y += grant-table.o features.o events.o | 5 | obj-y += grant-table.o features.o events.o balloon.o |
6 | obj-y += xenbus/ | 6 | obj-y += xenbus/ |
7 | 7 | ||
8 | nostackp := $(call cc-option, -fno-stack-protector) | 8 | nostackp := $(call cc-option, -fno-stack-protector) |
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index d6886d90ccfd..a56776dbe095 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c | |||
@@ -359,6 +359,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages) | |||
359 | 359 | ||
360 | set_phys_to_machine(pfn, frame_list[i]); | 360 | set_phys_to_machine(pfn, frame_list[i]); |
361 | 361 | ||
362 | #ifdef CONFIG_XEN_HAVE_PVMMU | ||
362 | /* Link back into the page tables if not highmem. */ | 363 | /* Link back into the page tables if not highmem. */ |
363 | if (xen_pv_domain() && !PageHighMem(page)) { | 364 | if (xen_pv_domain() && !PageHighMem(page)) { |
364 | int ret; | 365 | int ret; |
@@ -368,6 +369,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages) | |||
368 | 0); | 369 | 0); |
369 | BUG_ON(ret); | 370 | BUG_ON(ret); |
370 | } | 371 | } |
372 | #endif | ||
371 | 373 | ||
372 | /* Relinquish the page back to the allocator. */ | 374 | /* Relinquish the page back to the allocator. */ |
373 | ClearPageReserved(page); | 375 | ClearPageReserved(page); |
@@ -416,13 +418,14 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) | |||
416 | 418 | ||
417 | scrub_page(page); | 419 | scrub_page(page); |
418 | 420 | ||
421 | #ifdef CONFIG_XEN_HAVE_PVMMU | ||
419 | if (xen_pv_domain() && !PageHighMem(page)) { | 422 | if (xen_pv_domain() && !PageHighMem(page)) { |
420 | ret = HYPERVISOR_update_va_mapping( | 423 | ret = HYPERVISOR_update_va_mapping( |
421 | (unsigned long)__va(pfn << PAGE_SHIFT), | 424 | (unsigned long)__va(pfn << PAGE_SHIFT), |
422 | __pte_ma(0), 0); | 425 | __pte_ma(0), 0); |
423 | BUG_ON(ret); | 426 | BUG_ON(ret); |
424 | } | 427 | } |
425 | 428 | #endif | |
426 | } | 429 | } |
427 | 430 | ||
428 | /* Ensure that ballooned highmem pages don't have kmaps. */ | 431 | /* Ensure that ballooned highmem pages don't have kmaps. */ |
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 8adb9cc267f9..b9d08987a5a5 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c | |||
@@ -33,11 +33,14 @@ | |||
33 | #include <xen/features.h> | 33 | #include <xen/features.h> |
34 | #include <xen/page.h> | 34 | #include <xen/page.h> |
35 | #include <xen/xen-ops.h> | 35 | #include <xen/xen-ops.h> |
36 | #include <xen/balloon.h> | ||
36 | 37 | ||
37 | #include "privcmd.h" | 38 | #include "privcmd.h" |
38 | 39 | ||
39 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
40 | 41 | ||
42 | #define PRIV_VMA_LOCKED ((void *)1) | ||
43 | |||
41 | #ifndef HAVE_ARCH_PRIVCMD_MMAP | 44 | #ifndef HAVE_ARCH_PRIVCMD_MMAP |
42 | static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma); | 45 | static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma); |
43 | #endif | 46 | #endif |
@@ -178,7 +181,7 @@ static int mmap_mfn_range(void *data, void *state) | |||
178 | msg->va & PAGE_MASK, | 181 | msg->va & PAGE_MASK, |
179 | msg->mfn, msg->npages, | 182 | msg->mfn, msg->npages, |
180 | vma->vm_page_prot, | 183 | vma->vm_page_prot, |
181 | st->domain); | 184 | st->domain, NULL); |
182 | if (rc < 0) | 185 | if (rc < 0) |
183 | return rc; | 186 | return rc; |
184 | 187 | ||
@@ -199,6 +202,10 @@ static long privcmd_ioctl_mmap(void __user *udata) | |||
199 | if (!xen_initial_domain()) | 202 | if (!xen_initial_domain()) |
200 | return -EPERM; | 203 | return -EPERM; |
201 | 204 | ||
205 | /* We only support privcmd_ioctl_mmap_batch for auto translated. */ | ||
206 | if (xen_feature(XENFEAT_auto_translated_physmap)) | ||
207 | return -ENOSYS; | ||
208 | |||
202 | if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd))) | 209 | if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd))) |
203 | return -EFAULT; | 210 | return -EFAULT; |
204 | 211 | ||
@@ -246,6 +253,7 @@ struct mmap_batch_state { | |||
246 | domid_t domain; | 253 | domid_t domain; |
247 | unsigned long va; | 254 | unsigned long va; |
248 | struct vm_area_struct *vma; | 255 | struct vm_area_struct *vma; |
256 | int index; | ||
249 | /* A tristate: | 257 | /* A tristate: |
250 | * 0 for no errors | 258 | * 0 for no errors |
251 | * 1 if at least one error has happened (and no | 259 | * 1 if at least one error has happened (and no |
@@ -260,14 +268,24 @@ struct mmap_batch_state { | |||
260 | xen_pfn_t __user *user_mfn; | 268 | xen_pfn_t __user *user_mfn; |
261 | }; | 269 | }; |
262 | 270 | ||
271 | /* auto translated dom0 note: if domU being created is PV, then mfn is | ||
272 | * mfn(addr on bus). If it's auto xlated, then mfn is pfn (input to HAP). | ||
273 | */ | ||
263 | static int mmap_batch_fn(void *data, void *state) | 274 | static int mmap_batch_fn(void *data, void *state) |
264 | { | 275 | { |
265 | xen_pfn_t *mfnp = data; | 276 | xen_pfn_t *mfnp = data; |
266 | struct mmap_batch_state *st = state; | 277 | struct mmap_batch_state *st = state; |
278 | struct vm_area_struct *vma = st->vma; | ||
279 | struct page **pages = vma->vm_private_data; | ||
280 | struct page *cur_page = NULL; | ||
267 | int ret; | 281 | int ret; |
268 | 282 | ||
283 | if (xen_feature(XENFEAT_auto_translated_physmap)) | ||
284 | cur_page = pages[st->index++]; | ||
285 | |||
269 | ret = xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1, | 286 | ret = xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1, |
270 | st->vma->vm_page_prot, st->domain); | 287 | st->vma->vm_page_prot, st->domain, |
288 | &cur_page); | ||
271 | 289 | ||
272 | /* Store error code for second pass. */ | 290 | /* Store error code for second pass. */ |
273 | *(st->err++) = ret; | 291 | *(st->err++) = ret; |
@@ -303,6 +321,32 @@ static int mmap_return_errors_v1(void *data, void *state) | |||
303 | return __put_user(*mfnp, st->user_mfn++); | 321 | return __put_user(*mfnp, st->user_mfn++); |
304 | } | 322 | } |
305 | 323 | ||
324 | /* Allocate pfns that are then mapped with gmfns from foreign domid. Update | ||
325 | * the vma with the page info to use later. | ||
326 | * Returns: 0 if success, otherwise -errno | ||
327 | */ | ||
328 | static int alloc_empty_pages(struct vm_area_struct *vma, int numpgs) | ||
329 | { | ||
330 | int rc; | ||
331 | struct page **pages; | ||
332 | |||
333 | pages = kcalloc(numpgs, sizeof(pages[0]), GFP_KERNEL); | ||
334 | if (pages == NULL) | ||
335 | return -ENOMEM; | ||
336 | |||
337 | rc = alloc_xenballooned_pages(numpgs, pages, 0); | ||
338 | if (rc != 0) { | ||
339 | pr_warn("%s Could not alloc %d pfns rc:%d\n", __func__, | ||
340 | numpgs, rc); | ||
341 | kfree(pages); | ||
342 | return -ENOMEM; | ||
343 | } | ||
344 | BUG_ON(vma->vm_private_data != PRIV_VMA_LOCKED); | ||
345 | vma->vm_private_data = pages; | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
306 | static struct vm_operations_struct privcmd_vm_ops; | 350 | static struct vm_operations_struct privcmd_vm_ops; |
307 | 351 | ||
308 | static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | 352 | static long privcmd_ioctl_mmap_batch(void __user *udata, int version) |
@@ -370,10 +414,18 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | |||
370 | up_write(&mm->mmap_sem); | 414 | up_write(&mm->mmap_sem); |
371 | goto out; | 415 | goto out; |
372 | } | 416 | } |
417 | if (xen_feature(XENFEAT_auto_translated_physmap)) { | ||
418 | ret = alloc_empty_pages(vma, m.num); | ||
419 | if (ret < 0) { | ||
420 | up_write(&mm->mmap_sem); | ||
421 | goto out; | ||
422 | } | ||
423 | } | ||
373 | 424 | ||
374 | state.domain = m.dom; | 425 | state.domain = m.dom; |
375 | state.vma = vma; | 426 | state.vma = vma; |
376 | state.va = m.addr; | 427 | state.va = m.addr; |
428 | state.index = 0; | ||
377 | state.global_error = 0; | 429 | state.global_error = 0; |
378 | state.err = err_array; | 430 | state.err = err_array; |
379 | 431 | ||
@@ -438,6 +490,19 @@ static long privcmd_ioctl(struct file *file, | |||
438 | return ret; | 490 | return ret; |
439 | } | 491 | } |
440 | 492 | ||
493 | static void privcmd_close(struct vm_area_struct *vma) | ||
494 | { | ||
495 | struct page **pages = vma->vm_private_data; | ||
496 | int numpgs = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | ||
497 | |||
498 | if (!xen_feature(XENFEAT_auto_translated_physmap || !numpgs || !pages)) | ||
499 | return; | ||
500 | |||
501 | xen_unmap_domain_mfn_range(vma, numpgs, pages); | ||
502 | free_xenballooned_pages(numpgs, pages); | ||
503 | kfree(pages); | ||
504 | } | ||
505 | |||
441 | static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 506 | static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
442 | { | 507 | { |
443 | printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n", | 508 | printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n", |
@@ -448,6 +513,7 @@ static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
448 | } | 513 | } |
449 | 514 | ||
450 | static struct vm_operations_struct privcmd_vm_ops = { | 515 | static struct vm_operations_struct privcmd_vm_ops = { |
516 | .close = privcmd_close, | ||
451 | .fault = privcmd_fault | 517 | .fault = privcmd_fault |
452 | }; | 518 | }; |
453 | 519 | ||
@@ -465,7 +531,7 @@ static int privcmd_mmap(struct file *file, struct vm_area_struct *vma) | |||
465 | 531 | ||
466 | static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma) | 532 | static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma) |
467 | { | 533 | { |
468 | return (xchg(&vma->vm_private_data, (void *)1) == NULL); | 534 | return !cmpxchg(&vma->vm_private_data, NULL, PRIV_VMA_LOCKED); |
469 | } | 535 | } |
470 | 536 | ||
471 | const struct file_operations xen_privcmd_fops = { | 537 | const struct file_operations xen_privcmd_fops = { |