Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'stable/for-linus-3.16-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull Xen fix from David Vrabel:
"Fix BUG when trying to expand the grant table. This seems to occur
often during boot with Ubuntu 14.04 PV guests"

* tag 'stable/for-linus-3.16-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
x86/xen: safely map and unmap grant frames when in atomic context

+106 -59
+5
arch/arm/xen/grant-table.c
··· 51 51 { 52 52 return -ENOSYS; 53 53 } 54 + 55 + int arch_gnttab_init(unsigned long nr_shared, unsigned long nr_status) 56 + { 57 + return 0; 58 + }
+92 -58
arch/x86/xen/grant-table.c
··· 36 36 37 37 #include <linux/sched.h> 38 38 #include <linux/mm.h> 39 + #include <linux/slab.h> 39 40 #include <linux/vmalloc.h> 40 41 41 42 #include <xen/interface/xen.h> 42 43 #include <xen/page.h> 43 44 #include <xen/grant_table.h> 45 + #include <xen/xen.h> 44 46 45 47 #include <asm/pgtable.h> 46 48 47 - static int map_pte_fn(pte_t *pte, struct page *pmd_page, 48 - unsigned long addr, void *data) 49 - { 50 - unsigned long **frames = (unsigned long **)data; 51 - 52 - set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL)); 53 - (*frames)++; 54 - return 0; 55 - } 56 - 57 - /* 58 - * This function is used to map shared frames to store grant status. It is 59 - * different from map_pte_fn above, the frames type here is uint64_t. 60 - */ 61 - static int map_pte_fn_status(pte_t *pte, struct page *pmd_page, 62 - unsigned long addr, void *data) 63 - { 64 - uint64_t **frames = (uint64_t **)data; 65 - 66 - set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL)); 67 - (*frames)++; 68 - return 0; 69 - } 70 - 71 - static int unmap_pte_fn(pte_t *pte, struct page *pmd_page, 72 - unsigned long addr, void *data) 73 - { 74 - 75 - set_pte_at(&init_mm, addr, pte, __pte(0)); 76 - return 0; 77 - } 49 + static struct gnttab_vm_area { 50 + struct vm_struct *area; 51 + pte_t **ptes; 52 + } gnttab_shared_vm_area, gnttab_status_vm_area; 78 53 79 54 int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes, 80 55 unsigned long max_nr_gframes, 81 56 void **__shared) 82 57 { 83 - int rc; 84 58 void *shared = *__shared; 59 + unsigned long addr; 60 + unsigned long i; 85 61 86 - if (shared == NULL) { 87 - struct vm_struct *area = 88 - alloc_vm_area(PAGE_SIZE * max_nr_gframes, NULL); 89 - BUG_ON(area == NULL); 90 - shared = area->addr; 91 - *__shared = shared; 62 + if (shared == NULL) 63 + *__shared = shared = gnttab_shared_vm_area.area->addr; 64 + 65 + addr = (unsigned long)shared; 66 + 67 + for (i = 0; i < nr_gframes; i++) { 68 + set_pte_at(&init_mm, addr, gnttab_shared_vm_area.ptes[i], 69 + mfn_pte(frames[i], PAGE_KERNEL)); 70 + addr += PAGE_SIZE; 92 71 } 93 72 94 - rc = apply_to_page_range(&init_mm, (unsigned long)shared, 95 - PAGE_SIZE * nr_gframes, 96 - map_pte_fn, &frames); 97 - return rc; 73 + return 0; 98 74 } 99 75 100 76 int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes, 101 77 unsigned long max_nr_gframes, 102 78 grant_status_t **__shared) 103 79 { 104 - int rc; 105 80 grant_status_t *shared = *__shared; 81 + unsigned long addr; 82 + unsigned long i; 106 83 107 - if (shared == NULL) { 108 - /* No need to pass in PTE as we are going to do it 109 - * in apply_to_page_range anyhow. */ 110 - struct vm_struct *area = 111 - alloc_vm_area(PAGE_SIZE * max_nr_gframes, NULL); 112 - BUG_ON(area == NULL); 113 - shared = area->addr; 114 - *__shared = shared; 84 + if (shared == NULL) 85 + *__shared = shared = gnttab_status_vm_area.area->addr; 86 + 87 + addr = (unsigned long)shared; 88 + 89 + for (i = 0; i < nr_gframes; i++) { 90 + set_pte_at(&init_mm, addr, gnttab_status_vm_area.ptes[i], 91 + mfn_pte(frames[i], PAGE_KERNEL)); 92 + addr += PAGE_SIZE; 115 93 } 116 94 117 - rc = apply_to_page_range(&init_mm, (unsigned long)shared, 118 - PAGE_SIZE * nr_gframes, 119 - map_pte_fn_status, &frames); 120 - return rc; 95 + return 0; 121 96 } 122 97 123 98 void arch_gnttab_unmap(void *shared, unsigned long nr_gframes) 124 99 { 125 - apply_to_page_range(&init_mm, (unsigned long)shared, 126 - PAGE_SIZE * nr_gframes, unmap_pte_fn, NULL); 100 + pte_t **ptes; 101 + unsigned long addr; 102 + unsigned long i; 103 + 104 + if (shared == gnttab_status_vm_area.area->addr) 105 + ptes = gnttab_status_vm_area.ptes; 106 + else 107 + ptes = gnttab_shared_vm_area.ptes; 108 + 109 + addr = (unsigned long)shared; 110 + 111 + for (i = 0; i < nr_gframes; i++) { 112 + set_pte_at(&init_mm, addr, ptes[i], __pte(0)); 113 + addr += PAGE_SIZE; 114 + } 127 115 } 116 + 117 + static int arch_gnttab_valloc(struct gnttab_vm_area *area, unsigned nr_frames) 118 + { 119 + area->ptes = kmalloc(sizeof(pte_t *) * nr_frames, GFP_KERNEL); 120 + if (area->ptes == NULL) 121 + return -ENOMEM; 122 + 123 + area->area = alloc_vm_area(PAGE_SIZE * nr_frames, area->ptes); 124 + if (area->area == NULL) { 125 + kfree(area->ptes); 126 + return -ENOMEM; 127 + } 128 + 129 + return 0; 130 + } 131 + 132 + static void arch_gnttab_vfree(struct gnttab_vm_area *area) 133 + { 134 + free_vm_area(area->area); 135 + kfree(area->ptes); 136 + } 137 + 138 + int arch_gnttab_init(unsigned long nr_shared, unsigned long nr_status) 139 + { 140 + int ret; 141 + 142 + if (!xen_pv_domain()) 143 + return 0; 144 + 145 + ret = arch_gnttab_valloc(&gnttab_shared_vm_area, nr_shared); 146 + if (ret < 0) 147 + return ret; 148 + 149 + /* 150 + * Always allocate the space for the status frames in case 151 + * we're migrated to a host with V2 support. 152 + */ 153 + ret = arch_gnttab_valloc(&gnttab_status_vm_area, nr_status); 154 + if (ret < 0) 155 + goto err; 156 + 157 + return 0; 158 + err: 159 + arch_gnttab_vfree(&gnttab_shared_vm_area); 160 + return -ENOMEM; 161 + } 162 + 128 163 #ifdef CONFIG_XEN_PVH 129 164 #include <xen/balloon.h> 130 165 #include <xen/events.h> 131 - #include <xen/xen.h> 132 166 #include <linux/slab.h> 133 167 static int __init xlated_setup_gnttab_pages(void) 134 168 {
+8 -1
drivers/xen/grant-table.c
··· 1195 1195 int gnttab_init(void) 1196 1196 { 1197 1197 int i; 1198 + unsigned long max_nr_grant_frames; 1198 1199 unsigned int max_nr_glist_frames, nr_glist_frames; 1199 1200 unsigned int nr_init_grefs; 1200 1201 int ret; 1201 1202 1202 1203 gnttab_request_version(); 1204 + max_nr_grant_frames = gnttab_max_grant_frames(); 1203 1205 nr_grant_frames = 1; 1204 1206 1205 1207 /* Determine the maximum number of frames required for the 1206 1208 * grant reference free list on the current hypervisor. 1207 1209 */ 1208 1210 BUG_ON(grefs_per_grant_frame == 0); 1209 - max_nr_glist_frames = (gnttab_max_grant_frames() * 1211 + max_nr_glist_frames = (max_nr_grant_frames * 1210 1212 grefs_per_grant_frame / RPP); 1211 1213 1212 1214 gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *), ··· 1224 1222 goto ini_nomem; 1225 1223 } 1226 1224 } 1225 + 1226 + ret = arch_gnttab_init(max_nr_grant_frames, 1227 + nr_status_frames(max_nr_grant_frames)); 1228 + if (ret < 0) 1229 + goto ini_nomem; 1227 1230 1228 1231 if (gnttab_setup() < 0) { 1229 1232 ret = -ENODEV;
+1
include/xen/grant_table.h
··· 170 170 unmap->dev_bus_addr = 0; 171 171 } 172 172 173 + int arch_gnttab_init(unsigned long nr_shared, unsigned long nr_status); 173 174 int arch_gnttab_map_shared(xen_pfn_t *frames, unsigned long nr_gframes, 174 175 unsigned long max_nr_gframes, 175 176 void **__shared);