.. | .. |
---|
33 | 33 | |
---|
34 | 34 | #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt |
---|
35 | 35 | |
---|
36 | | -#include <linux/bootmem.h> |
---|
| 36 | +#include <linux/memblock.h> |
---|
37 | 37 | #include <linux/sched.h> |
---|
38 | 38 | #include <linux/mm.h> |
---|
39 | 39 | #include <linux/slab.h> |
---|
.. | .. |
---|
64 | 64 | #include <asm/xen/hypercall.h> |
---|
65 | 65 | #include <asm/xen/interface.h> |
---|
66 | 66 | |
---|
67 | | -#include <asm/pgtable.h> |
---|
68 | 67 | #include <asm/sync_bitops.h> |
---|
69 | 68 | |
---|
70 | 69 | /* External tools reserve first few grant table entries. */ |
---|
.. | .. |
---|
135 | 134 | */ |
---|
136 | 135 | unsigned long (*end_foreign_transfer_ref)(grant_ref_t ref); |
---|
137 | 136 | /* |
---|
138 | | - * Query the status of a grant entry. Ref parameter is reference of |
---|
139 | | - * queried grant entry, return value is the status of queried entry. |
---|
140 | | - * Detailed status(writing/reading) can be gotten from the return value |
---|
141 | | - * by bit operations. |
---|
| 137 | + * Read the frame number related to a given grant reference. |
---|
142 | 138 | */ |
---|
143 | | - int (*query_foreign_access)(grant_ref_t ref); |
---|
| 139 | + unsigned long (*read_frame)(grant_ref_t ref); |
---|
144 | 140 | }; |
---|
145 | 141 | |
---|
146 | 142 | struct unmap_refs_callback_data { |
---|
.. | .. |
---|
285 | 281 | } |
---|
286 | 282 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access); |
---|
287 | 283 | |
---|
288 | | -static int gnttab_query_foreign_access_v1(grant_ref_t ref) |
---|
289 | | -{ |
---|
290 | | - return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing); |
---|
291 | | -} |
---|
292 | | - |
---|
293 | | -static int gnttab_query_foreign_access_v2(grant_ref_t ref) |
---|
294 | | -{ |
---|
295 | | - return grstatus[ref] & (GTF_reading|GTF_writing); |
---|
296 | | -} |
---|
297 | | - |
---|
298 | | -int gnttab_query_foreign_access(grant_ref_t ref) |
---|
299 | | -{ |
---|
300 | | - return gnttab_interface->query_foreign_access(ref); |
---|
301 | | -} |
---|
302 | | -EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); |
---|
303 | | - |
---|
304 | 284 | static int gnttab_end_foreign_access_ref_v1(grant_ref_t ref, int readonly) |
---|
305 | 285 | { |
---|
306 | 286 | u16 flags, nflags; |
---|
.. | .. |
---|
354 | 334 | } |
---|
355 | 335 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref); |
---|
356 | 336 | |
---|
| 337 | +static unsigned long gnttab_read_frame_v1(grant_ref_t ref) |
---|
| 338 | +{ |
---|
| 339 | + return gnttab_shared.v1[ref].frame; |
---|
| 340 | +} |
---|
| 341 | + |
---|
| 342 | +static unsigned long gnttab_read_frame_v2(grant_ref_t ref) |
---|
| 343 | +{ |
---|
| 344 | + return gnttab_shared.v2[ref].full_page.frame; |
---|
| 345 | +} |
---|
| 346 | + |
---|
357 | 347 | struct deferred_entry { |
---|
358 | 348 | struct list_head list; |
---|
359 | 349 | grant_ref_t ref; |
---|
.. | .. |
---|
383 | 373 | spin_unlock_irqrestore(&gnttab_list_lock, flags); |
---|
384 | 374 | if (_gnttab_end_foreign_access_ref(entry->ref, entry->ro)) { |
---|
385 | 375 | put_free_entry(entry->ref); |
---|
386 | | - if (entry->page) { |
---|
387 | | - pr_debug("freeing g.e. %#x (pfn %#lx)\n", |
---|
388 | | - entry->ref, page_to_pfn(entry->page)); |
---|
389 | | - put_page(entry->page); |
---|
390 | | - } else |
---|
391 | | - pr_info("freeing g.e. %#x\n", entry->ref); |
---|
| 376 | + pr_debug("freeing g.e. %#x (pfn %#lx)\n", |
---|
| 377 | + entry->ref, page_to_pfn(entry->page)); |
---|
| 378 | + put_page(entry->page); |
---|
392 | 379 | kfree(entry); |
---|
393 | 380 | entry = NULL; |
---|
394 | 381 | } else { |
---|
.. | .. |
---|
413 | 400 | static void gnttab_add_deferred(grant_ref_t ref, bool readonly, |
---|
414 | 401 | struct page *page) |
---|
415 | 402 | { |
---|
416 | | - struct deferred_entry *entry = kmalloc(sizeof(*entry), GFP_ATOMIC); |
---|
| 403 | + struct deferred_entry *entry; |
---|
| 404 | + gfp_t gfp = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; |
---|
417 | 405 | const char *what = KERN_WARNING "leaking"; |
---|
| 406 | + |
---|
| 407 | + entry = kmalloc(sizeof(*entry), gfp); |
---|
| 408 | + if (!page) { |
---|
| 409 | + unsigned long gfn = gnttab_interface->read_frame(ref); |
---|
| 410 | + |
---|
| 411 | + page = pfn_to_page(gfn_to_pfn(gfn)); |
---|
| 412 | + get_page(page); |
---|
| 413 | + } |
---|
418 | 414 | |
---|
419 | 415 | if (entry) { |
---|
420 | 416 | unsigned long flags; |
---|
.. | .. |
---|
436 | 432 | what, ref, page ? page_to_pfn(page) : -1); |
---|
437 | 433 | } |
---|
438 | 434 | |
---|
| 435 | +int gnttab_try_end_foreign_access(grant_ref_t ref) |
---|
| 436 | +{ |
---|
| 437 | + int ret = _gnttab_end_foreign_access_ref(ref, 0); |
---|
| 438 | + |
---|
| 439 | + if (ret) |
---|
| 440 | + put_free_entry(ref); |
---|
| 441 | + |
---|
| 442 | + return ret; |
---|
| 443 | +} |
---|
| 444 | +EXPORT_SYMBOL_GPL(gnttab_try_end_foreign_access); |
---|
| 445 | + |
---|
439 | 446 | void gnttab_end_foreign_access(grant_ref_t ref, int readonly, |
---|
440 | 447 | unsigned long page) |
---|
441 | 448 | { |
---|
442 | | - if (gnttab_end_foreign_access_ref(ref, readonly)) { |
---|
443 | | - put_free_entry(ref); |
---|
| 449 | + if (gnttab_try_end_foreign_access(ref)) { |
---|
444 | 450 | if (page != 0) |
---|
445 | 451 | put_page(virt_to_page(page)); |
---|
446 | 452 | } else |
---|
.. | .. |
---|
664 | 670 | unsigned int nr_glist_frames, new_nr_glist_frames; |
---|
665 | 671 | unsigned int grefs_per_frame; |
---|
666 | 672 | |
---|
667 | | - BUG_ON(gnttab_interface == NULL); |
---|
668 | 673 | grefs_per_frame = gnttab_interface->grefs_per_grant_frame; |
---|
669 | 674 | |
---|
670 | 675 | new_nr_grant_frames = nr_grant_frames + more_frames; |
---|
.. | .. |
---|
803 | 808 | { |
---|
804 | 809 | int ret; |
---|
805 | 810 | |
---|
806 | | - ret = alloc_xenballooned_pages(nr_pages, pages); |
---|
| 811 | + ret = xen_alloc_unpopulated_pages(nr_pages, pages); |
---|
807 | 812 | if (ret < 0) |
---|
808 | 813 | return ret; |
---|
809 | 814 | |
---|
.. | .. |
---|
814 | 819 | return ret; |
---|
815 | 820 | } |
---|
816 | 821 | EXPORT_SYMBOL_GPL(gnttab_alloc_pages); |
---|
| 822 | + |
---|
| 823 | +#ifdef CONFIG_XEN_UNPOPULATED_ALLOC |
---|
| 824 | +static inline void cache_init(struct gnttab_page_cache *cache) |
---|
| 825 | +{ |
---|
| 826 | + cache->pages = NULL; |
---|
| 827 | +} |
---|
| 828 | + |
---|
| 829 | +static inline bool cache_empty(struct gnttab_page_cache *cache) |
---|
| 830 | +{ |
---|
| 831 | + return !cache->pages; |
---|
| 832 | +} |
---|
| 833 | + |
---|
| 834 | +static inline struct page *cache_deq(struct gnttab_page_cache *cache) |
---|
| 835 | +{ |
---|
| 836 | + struct page *page; |
---|
| 837 | + |
---|
| 838 | + page = cache->pages; |
---|
| 839 | + cache->pages = page->zone_device_data; |
---|
| 840 | + |
---|
| 841 | + return page; |
---|
| 842 | +} |
---|
| 843 | + |
---|
| 844 | +static inline void cache_enq(struct gnttab_page_cache *cache, struct page *page) |
---|
| 845 | +{ |
---|
| 846 | + page->zone_device_data = cache->pages; |
---|
| 847 | + cache->pages = page; |
---|
| 848 | +} |
---|
| 849 | +#else |
---|
| 850 | +static inline void cache_init(struct gnttab_page_cache *cache) |
---|
| 851 | +{ |
---|
| 852 | + INIT_LIST_HEAD(&cache->pages); |
---|
| 853 | +} |
---|
| 854 | + |
---|
| 855 | +static inline bool cache_empty(struct gnttab_page_cache *cache) |
---|
| 856 | +{ |
---|
| 857 | + return list_empty(&cache->pages); |
---|
| 858 | +} |
---|
| 859 | + |
---|
| 860 | +static inline struct page *cache_deq(struct gnttab_page_cache *cache) |
---|
| 861 | +{ |
---|
| 862 | + struct page *page; |
---|
| 863 | + |
---|
| 864 | + page = list_first_entry(&cache->pages, struct page, lru); |
---|
| 865 | + list_del(&page->lru); |
---|
| 866 | + |
---|
| 867 | + return page; |
---|
| 868 | +} |
---|
| 869 | + |
---|
| 870 | +static inline void cache_enq(struct gnttab_page_cache *cache, struct page *page) |
---|
| 871 | +{ |
---|
| 872 | + list_add(&page->lru, &cache->pages); |
---|
| 873 | +} |
---|
| 874 | +#endif |
---|
| 875 | + |
---|
| 876 | +void gnttab_page_cache_init(struct gnttab_page_cache *cache) |
---|
| 877 | +{ |
---|
| 878 | + spin_lock_init(&cache->lock); |
---|
| 879 | + cache_init(cache); |
---|
| 880 | + cache->num_pages = 0; |
---|
| 881 | +} |
---|
| 882 | +EXPORT_SYMBOL_GPL(gnttab_page_cache_init); |
---|
| 883 | + |
---|
| 884 | +int gnttab_page_cache_get(struct gnttab_page_cache *cache, struct page **page) |
---|
| 885 | +{ |
---|
| 886 | + unsigned long flags; |
---|
| 887 | + |
---|
| 888 | + spin_lock_irqsave(&cache->lock, flags); |
---|
| 889 | + |
---|
| 890 | + if (cache_empty(cache)) { |
---|
| 891 | + spin_unlock_irqrestore(&cache->lock, flags); |
---|
| 892 | + return gnttab_alloc_pages(1, page); |
---|
| 893 | + } |
---|
| 894 | + |
---|
| 895 | + page[0] = cache_deq(cache); |
---|
| 896 | + cache->num_pages--; |
---|
| 897 | + |
---|
| 898 | + spin_unlock_irqrestore(&cache->lock, flags); |
---|
| 899 | + |
---|
| 900 | + return 0; |
---|
| 901 | +} |
---|
| 902 | +EXPORT_SYMBOL_GPL(gnttab_page_cache_get); |
---|
| 903 | + |
---|
| 904 | +void gnttab_page_cache_put(struct gnttab_page_cache *cache, struct page **page, |
---|
| 905 | + unsigned int num) |
---|
| 906 | +{ |
---|
| 907 | + unsigned long flags; |
---|
| 908 | + unsigned int i; |
---|
| 909 | + |
---|
| 910 | + spin_lock_irqsave(&cache->lock, flags); |
---|
| 911 | + |
---|
| 912 | + for (i = 0; i < num; i++) |
---|
| 913 | + cache_enq(cache, page[i]); |
---|
| 914 | + cache->num_pages += num; |
---|
| 915 | + |
---|
| 916 | + spin_unlock_irqrestore(&cache->lock, flags); |
---|
| 917 | +} |
---|
| 918 | +EXPORT_SYMBOL_GPL(gnttab_page_cache_put); |
---|
| 919 | + |
---|
| 920 | +void gnttab_page_cache_shrink(struct gnttab_page_cache *cache, unsigned int num) |
---|
| 921 | +{ |
---|
| 922 | + struct page *page[10]; |
---|
| 923 | + unsigned int i = 0; |
---|
| 924 | + unsigned long flags; |
---|
| 925 | + |
---|
| 926 | + spin_lock_irqsave(&cache->lock, flags); |
---|
| 927 | + |
---|
| 928 | + while (cache->num_pages > num) { |
---|
| 929 | + page[i] = cache_deq(cache); |
---|
| 930 | + cache->num_pages--; |
---|
| 931 | + if (++i == ARRAY_SIZE(page)) { |
---|
| 932 | + spin_unlock_irqrestore(&cache->lock, flags); |
---|
| 933 | + gnttab_free_pages(i, page); |
---|
| 934 | + i = 0; |
---|
| 935 | + spin_lock_irqsave(&cache->lock, flags); |
---|
| 936 | + } |
---|
| 937 | + } |
---|
| 938 | + |
---|
| 939 | + spin_unlock_irqrestore(&cache->lock, flags); |
---|
| 940 | + |
---|
| 941 | + if (i != 0) |
---|
| 942 | + gnttab_free_pages(i, page); |
---|
| 943 | +} |
---|
| 944 | +EXPORT_SYMBOL_GPL(gnttab_page_cache_shrink); |
---|
817 | 945 | |
---|
818 | 946 | void gnttab_pages_clear_private(int nr_pages, struct page **pages) |
---|
819 | 947 | { |
---|
.. | .. |
---|
838 | 966 | void gnttab_free_pages(int nr_pages, struct page **pages) |
---|
839 | 967 | { |
---|
840 | 968 | gnttab_pages_clear_private(nr_pages, pages); |
---|
841 | | - free_xenballooned_pages(nr_pages, pages); |
---|
| 969 | + xen_free_unpopulated_pages(nr_pages, pages); |
---|
842 | 970 | } |
---|
843 | 971 | EXPORT_SYMBOL_GPL(gnttab_free_pages); |
---|
844 | 972 | |
---|
.. | .. |
---|
852 | 980 | unsigned long pfn, start_pfn; |
---|
853 | 981 | size_t size; |
---|
854 | 982 | int i, ret; |
---|
| 983 | + |
---|
| 984 | + if (args->nr_pages < 0 || args->nr_pages > (INT_MAX >> PAGE_SHIFT)) |
---|
| 985 | + return -ENOMEM; |
---|
855 | 986 | |
---|
856 | 987 | size = args->nr_pages << PAGE_SHIFT; |
---|
857 | 988 | if (args->coherent) |
---|
.. | .. |
---|
1160 | 1291 | |
---|
1161 | 1292 | static unsigned int nr_status_frames(unsigned int nr_grant_frames) |
---|
1162 | 1293 | { |
---|
1163 | | - BUG_ON(gnttab_interface == NULL); |
---|
1164 | 1294 | return gnttab_frames(nr_grant_frames, SPP); |
---|
1165 | 1295 | } |
---|
1166 | 1296 | |
---|
.. | .. |
---|
1297 | 1427 | .update_entry = gnttab_update_entry_v1, |
---|
1298 | 1428 | .end_foreign_access_ref = gnttab_end_foreign_access_ref_v1, |
---|
1299 | 1429 | .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v1, |
---|
1300 | | - .query_foreign_access = gnttab_query_foreign_access_v1, |
---|
| 1430 | + .read_frame = gnttab_read_frame_v1, |
---|
1301 | 1431 | }; |
---|
1302 | 1432 | |
---|
1303 | 1433 | static const struct gnttab_ops gnttab_v2_ops = { |
---|
.. | .. |
---|
1309 | 1439 | .update_entry = gnttab_update_entry_v2, |
---|
1310 | 1440 | .end_foreign_access_ref = gnttab_end_foreign_access_ref_v2, |
---|
1311 | 1441 | .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v2, |
---|
1312 | | - .query_foreign_access = gnttab_query_foreign_access_v2, |
---|
| 1442 | + .read_frame = gnttab_read_frame_v2, |
---|
1313 | 1443 | }; |
---|
1314 | 1444 | |
---|
1315 | 1445 | static bool gnttab_need_v2(void) |
---|
.. | .. |
---|
1363 | 1493 | if (xen_feature(XENFEAT_auto_translated_physmap) && gnttab_shared.addr == NULL) { |
---|
1364 | 1494 | gnttab_shared.addr = xen_auto_xlat_grant_frames.vaddr; |
---|
1365 | 1495 | if (gnttab_shared.addr == NULL) { |
---|
1366 | | - pr_warn("gnttab share frames (addr=0x%08lx) is not mapped!\n", |
---|
1367 | | - (unsigned long)xen_auto_xlat_grant_frames.vaddr); |
---|
| 1496 | + pr_warn("gnttab share frames is not mapped!\n"); |
---|
1368 | 1497 | return -ENOMEM; |
---|
1369 | 1498 | } |
---|
1370 | 1499 | } |
---|
.. | .. |
---|
1389 | 1518 | int rc; |
---|
1390 | 1519 | unsigned int cur, extra; |
---|
1391 | 1520 | |
---|
1392 | | - BUG_ON(gnttab_interface == NULL); |
---|
1393 | 1521 | cur = nr_grant_frames; |
---|
1394 | 1522 | extra = ((req_entries + gnttab_interface->grefs_per_grant_frame - 1) / |
---|
1395 | 1523 | gnttab_interface->grefs_per_grant_frame); |
---|
.. | .. |
---|
1424 | 1552 | /* Determine the maximum number of frames required for the |
---|
1425 | 1553 | * grant reference free list on the current hypervisor. |
---|
1426 | 1554 | */ |
---|
1427 | | - BUG_ON(gnttab_interface == NULL); |
---|
1428 | 1555 | max_nr_glist_frames = (max_nr_grant_frames * |
---|
1429 | 1556 | gnttab_interface->grefs_per_grant_frame / RPP); |
---|
1430 | 1557 | |
---|