|
@@ -17,6 +17,7 @@
|
|
#include <linux/workqueue.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/file.h>
|
|
#include <linux/file.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
|
|
+#include <linux/vmalloc.h>
|
|
|
|
|
|
#include <linux/net.h>
|
|
#include <linux/net.h>
|
|
#include <linux/if_packet.h>
|
|
#include <linux/if_packet.h>
|
|
@@ -699,18 +700,30 @@ static void handle_rx_net(struct vhost_work *work)
|
|
handle_rx(net);
|
|
handle_rx(net);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void vhost_net_free(void *addr)
|
|
|
|
+{
|
|
|
|
+ if (is_vmalloc_addr(addr))
|
|
|
|
+ vfree(addr);
|
|
|
|
+ else
|
|
|
|
+ kfree(addr);
|
|
|
|
+}
|
|
|
|
+
|
|
static int vhost_net_open(struct inode *inode, struct file *f)
|
|
static int vhost_net_open(struct inode *inode, struct file *f)
|
|
{
|
|
{
|
|
- struct vhost_net *n = kmalloc(sizeof *n, GFP_KERNEL);
|
|
|
|
|
|
+ struct vhost_net *n;
|
|
struct vhost_dev *dev;
|
|
struct vhost_dev *dev;
|
|
struct vhost_virtqueue **vqs;
|
|
struct vhost_virtqueue **vqs;
|
|
int i;
|
|
int i;
|
|
|
|
|
|
- if (!n)
|
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ n = kmalloc(sizeof *n, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
|
|
|
|
+ if (!n) {
|
|
|
|
+ n = vmalloc(sizeof *n);
|
|
|
|
+ if (!n)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
vqs = kmalloc(VHOST_NET_VQ_MAX * sizeof(*vqs), GFP_KERNEL);
|
|
vqs = kmalloc(VHOST_NET_VQ_MAX * sizeof(*vqs), GFP_KERNEL);
|
|
if (!vqs) {
|
|
if (!vqs) {
|
|
- kfree(n);
|
|
|
|
|
|
+ vhost_net_free(n);
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -827,7 +840,7 @@ static int vhost_net_release(struct inode *inode, struct file *f)
|
|
* since jobs can re-queue themselves. */
|
|
* since jobs can re-queue themselves. */
|
|
vhost_net_flush(n);
|
|
vhost_net_flush(n);
|
|
kfree(n->dev.vqs);
|
|
kfree(n->dev.vqs);
|
|
- kfree(n);
|
|
|
|
|
|
+ vhost_net_free(n);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|