summaryrefslogtreecommitdiffstats
path: root/drivers/virt
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2018-04-18 09:24:49 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-04-23 07:41:55 -0400
commitfaf6a2a44164c0fb2c2a82692ab9051917514bce (patch)
treeb7ed81ebf85416b394564e24e2200aa751934358 /drivers/virt
parentf6f9885b0531163f72c7bf898a0ab1ba4c7d5de6 (diff)
virt: vbox: Use __get_free_pages instead of kmalloc for DMA32 memory
It is not possible to get DMA32 zone memory through kmalloc, causing the vboxguest driver to malfunction due to getting memory above 4G which the PCI device cannot handle. This commit changes the kmalloc calls where the 4G limit matters to using __get_free_pages() fixing vboxguest not working on x86_64 guests with more then 4G RAM. Cc: stable@vger.kernel.org Reported-by: Eloy Coto Pereiro <eloy.coto@gmail.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/virt')
-rw-r--r--drivers/virt/vboxguest/vboxguest_linux.c19
-rw-r--r--drivers/virt/vboxguest/vboxguest_utils.c5
2 files changed, 19 insertions, 5 deletions
diff --git a/drivers/virt/vboxguest/vboxguest_linux.c b/drivers/virt/vboxguest/vboxguest_linux.c
index 82e280d38cc2..398d22693234 100644
--- a/drivers/virt/vboxguest/vboxguest_linux.c
+++ b/drivers/virt/vboxguest/vboxguest_linux.c
@@ -87,6 +87,7 @@ static long vbg_misc_device_ioctl(struct file *filp, unsigned int req,
87 struct vbg_session *session = filp->private_data; 87 struct vbg_session *session = filp->private_data;
88 size_t returned_size, size; 88 size_t returned_size, size;
89 struct vbg_ioctl_hdr hdr; 89 struct vbg_ioctl_hdr hdr;
90 bool is_vmmdev_req;
90 int ret = 0; 91 int ret = 0;
91 void *buf; 92 void *buf;
92 93
@@ -106,8 +107,17 @@ static long vbg_misc_device_ioctl(struct file *filp, unsigned int req,
106 if (size > SZ_16M) 107 if (size > SZ_16M)
107 return -E2BIG; 108 return -E2BIG;
108 109
109 /* __GFP_DMA32 because IOCTL_VMMDEV_REQUEST passes this to the host */ 110 /*
110 buf = kmalloc(size, GFP_KERNEL | __GFP_DMA32); 111 * IOCTL_VMMDEV_REQUEST needs the buffer to be below 4G to avoid
112 * the need for a bounce-buffer and another copy later on.
113 */
114 is_vmmdev_req = (req & ~IOCSIZE_MASK) == VBG_IOCTL_VMMDEV_REQUEST(0) ||
115 req == VBG_IOCTL_VMMDEV_REQUEST_BIG;
116
117 if (is_vmmdev_req)
118 buf = vbg_req_alloc(size, VBG_IOCTL_HDR_TYPE_DEFAULT);
119 else
120 buf = kmalloc(size, GFP_KERNEL);
111 if (!buf) 121 if (!buf)
112 return -ENOMEM; 122 return -ENOMEM;
113 123
@@ -132,7 +142,10 @@ static long vbg_misc_device_ioctl(struct file *filp, unsigned int req,
132 ret = -EFAULT; 142 ret = -EFAULT;
133 143
134out: 144out:
135 kfree(buf); 145 if (is_vmmdev_req)
146 vbg_req_free(buf, size);
147 else
148 kfree(buf);
136 149
137 return ret; 150 return ret;
138} 151}
diff --git a/drivers/virt/vboxguest/vboxguest_utils.c b/drivers/virt/vboxguest/vboxguest_utils.c
index bad915463359..bf4474214b4d 100644
--- a/drivers/virt/vboxguest/vboxguest_utils.c
+++ b/drivers/virt/vboxguest/vboxguest_utils.c
@@ -65,8 +65,9 @@ VBG_LOG(vbg_debug, pr_debug);
65void *vbg_req_alloc(size_t len, enum vmmdev_request_type req_type) 65void *vbg_req_alloc(size_t len, enum vmmdev_request_type req_type)
66{ 66{
67 struct vmmdev_request_header *req; 67 struct vmmdev_request_header *req;
68 int order = get_order(PAGE_ALIGN(len));
68 69
69 req = kmalloc(len, GFP_KERNEL | __GFP_DMA32); 70 req = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA32, order);
70 if (!req) 71 if (!req)
71 return NULL; 72 return NULL;
72 73
@@ -87,7 +88,7 @@ void vbg_req_free(void *req, size_t len)
87 if (!req) 88 if (!req)
88 return; 89 return;
89 90
90 kfree(req); 91 free_pages((unsigned long)req, get_order(PAGE_ALIGN(len)));
91} 92}
92 93
93/* Note this function returns a VBox status code, not a negative errno!! */ 94/* Note this function returns a VBox status code, not a negative errno!! */