From mboxrd@z Thu Jan 1 00:00:00 1970 From: Dmitry Petuhov Subject: [PATCH 3.10] vhost-net: backport extend device allocation to 3.10 Date: Thu, 09 Oct 2014 08:41:23 +0400 Message-ID: <4028601.CyDXDFuQHy@rzn-it-01> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit Cc: kvm@vger.kernel.org, Eddie Chapman , Michael Mueller , Romain Francoise To: "Michael S. Tsirkin" Return-path: Received: from mail-lb0-f177.google.com ([209.85.217.177]:40763 "EHLO mail-lb0-f177.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751041AbaJIE6R (ORCPT ); Thu, 9 Oct 2014 00:58:17 -0400 Received: by mail-lb0-f177.google.com with SMTP id w7so408123lbi.8 for ; Wed, 08 Oct 2014 21:58:15 -0700 (PDT) Sender: kvm-owner@vger.kernel.org List-ID: From: Michael S. Tsirkin upstream commit 23cc5a991c7a9fb7e6d6550e65cee4f4173111c5 Michael Mueller provided a patch to reduce the size of vhost-net structure as some allocations could fail under memory pressure/fragmentation. We are still left with high order allocations though. This patch is handling the problem at the core level, allowing vhost structures to use vmalloc() if kmalloc() failed. As vmalloc() adds overhead on a critical network path, add __GFP_REPEAT to kzalloc() flags to do this fallback only when really needed. People are still looking at cleaner ways to handle the problem at the API level, probably passing in multiple iovecs. This hack seems consistent with approaches taken since then by drivers/vhost/scsi.c and net/core/dev.c Based on patch by Romain Francoise. Cc: Michael Mueller Signed-off-by: Romain Francoise Acked-by: Michael S. Tsirkin [mityapetuhov: backport to v3.10: vhost_net_free() in one more place] Signed-off-by: Dmitry Petuhov --- diff -uprN a/drivers/vhost/net.c b/drivers/vhost/net.c --- a/drivers/vhost/net.c 2014-10-09 06:45:08.336283258 +0400 +++ b/drivers/vhost/net.c 2014-10-09 06:51:21.796266607 +0400 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -707,18 +708,30 @@ static void handle_rx_net(struct vhost_w 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) { - struct vhost_net *n = kmalloc(sizeof *n, GFP_KERNEL); + struct vhost_net *n; struct vhost_dev *dev; struct vhost_virtqueue **vqs; int r, 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); if (!vqs) { - kfree(n); + vhost_net_free(n); return -ENOMEM; } @@ -737,7 +750,7 @@ static int vhost_net_open(struct inode * } r = vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX); if (r < 0) { - kfree(n); + vhost_net_free(n); kfree(vqs); return r; } @@ -840,7 +853,7 @@ static int vhost_net_release(struct inod * since jobs can re-queue themselves. */ vhost_net_flush(n); kfree(n->dev.vqs); - kfree(n); + vhost_net_free(n); return 0; }