From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id CB0C2A04C9 for ; Wed, 16 Sep 2020 13:26:20 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id AFC8B1C244; Wed, 16 Sep 2020 13:26:20 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 0DABD1C0C9; Wed, 16 Sep 2020 13:26:17 +0200 (CEST) IronPort-SDR: ycAfoD0LYkpDsykPhDbe+tHWAHQPZmiOWN8AFbxgZtKDIg1gQwg4CpM7YV46K9PZyBNQ0NL6Fg nYDmJbTUwDlg== X-IronPort-AV: E=McAfee;i="6000,8403,9745"; a="147196441" X-IronPort-AV: E=Sophos;i="5.76,432,1592895600"; d="scan'208";a="147196441" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Sep 2020 04:26:16 -0700 IronPort-SDR: ZH2oxq9AsP6/ynyaltEsu09LD/4l/IZVHdRCOoPF/W9Yo7Ca5CvnA3vIly3Eh+HyJubbySsU5S nvgX1+rZiftg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,432,1592895600"; d="scan'208";a="346194579" Received: from silpixa00399498.ir.intel.com (HELO silpixa00399498.ger.corp.intel.com) ([10.237.222.52]) by orsmga007.jf.intel.com with ESMTP; 16 Sep 2020 04:26:16 -0700 From: Anatoly Burakov To: dev@dpdk.org Cc: stable@dpdk.org Date: Wed, 16 Sep 2020 12:26:15 +0100 Message-Id: <4275aaf7d248f0e2a05ac21c05d682ce7ea4ad56.1600255570.git.anatoly.burakov@intel.com> X-Mailer: git-send-email 2.17.1 Subject: [dpdk-stable] [PATCH 18.11] vfio: map contiguous areas in one go X-BeenThere: stable@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches for DPDK stable branches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: stable-bounces@dpdk.org Sender: "stable" Currently, when we are creating DMA mappings for memory that's either external or is backed by hugepages in IOVA as PA mode, we assume that each page is necessarily discontiguous. This may not actually be the case, especially for external memory, where the user is able to create their own IOVA table and make it contiguous. This is a problem because VFIO has a limited number of DMA mappings, and it does not appear to concatenate them and treats each mapping as separate, even when they cover adjacent areas. Fix this so that we always map contiguous memory in a single chunk, as opposed to mapping each segment separately. Signed-off-by: Anatoly Burakov --- Notes: Resend for stable as original patch [1] no longer applies [1] http://patches.dpdk.org/patch/66041/ lib/librte_eal/linuxapp/eal/eal_vfio.c | 59 ++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/lib/librte_eal/linuxapp/eal/eal_vfio.c b/lib/librte_eal/linuxapp/eal/eal_vfio.c index 2f84e0f215..be969bbaac 100644 --- a/lib/librte_eal/linuxapp/eal/eal_vfio.c +++ b/lib/librte_eal/linuxapp/eal/eal_vfio.c @@ -510,9 +510,11 @@ static void vfio_mem_event_callback(enum rte_mem_event type, const void *addr, size_t len, void *arg __rte_unused) { + rte_iova_t iova_start, iova_expected; struct rte_memseg_list *msl; struct rte_memseg *ms; size_t cur_len = 0; + uint64_t va_start; msl = rte_mem_virt2memseg_list(addr); @@ -530,22 +532,63 @@ vfio_mem_event_callback(enum rte_mem_event type, const void *addr, size_t len, /* memsegs are contiguous in memory */ ms = rte_mem_virt2memseg(addr, msl); + + /* + * This memory is not guaranteed to be contiguous, but it still could + * be, or it could have some small contiguous chunks. Since the number + * of VFIO mappings is limited, and VFIO appears to not concatenate + * adjacent mappings, we have to do this ourselves. + * + * So, find contiguous chunks, then map them. + */ + va_start = ms->addr_64; + iova_start = iova_expected = ms->iova; while (cur_len < len) { + bool new_contig_area = ms->iova != iova_expected; + bool last_seg = (len - cur_len) == ms->len; + bool skip_last = false; + + /* only do mappings when current contiguous area ends */ + if (new_contig_area) { + if (type == RTE_MEM_EVENT_ALLOC) + vfio_dma_mem_map(default_vfio_cfg, va_start, + iova_start, + iova_expected - iova_start, 1); + else + vfio_dma_mem_map(default_vfio_cfg, va_start, + iova_start, + iova_expected - iova_start, 0); + va_start = ms->addr_64; + iova_start = ms->iova; + } /* some memory segments may have invalid IOVA */ if (ms->iova == RTE_BAD_IOVA) { RTE_LOG(DEBUG, EAL, "Memory segment at %p has bad IOVA, skipping\n", ms->addr); - goto next; + skip_last = true; } - if (type == RTE_MEM_EVENT_ALLOC) - vfio_dma_mem_map(default_vfio_cfg, ms->addr_64, - ms->iova, ms->len, 1); - else - vfio_dma_mem_map(default_vfio_cfg, ms->addr_64, - ms->iova, ms->len, 0); -next: + iova_expected = ms->iova + ms->len; cur_len += ms->len; ++ms; + + /* + * don't count previous segment, and don't attempt to + * dereference a potentially invalid pointer. + */ + if (skip_last && !last_seg) { + iova_expected = iova_start = ms->iova; + va_start = ms->addr_64; + } else if (!skip_last && last_seg) { + /* this is the last segment and we're not skipping */ + if (type == RTE_MEM_EVENT_ALLOC) + vfio_dma_mem_map(default_vfio_cfg, va_start, + iova_start, + iova_expected - iova_start, 1); + else + vfio_dma_mem_map(default_vfio_cfg, va_start, + iova_start, + iova_expected - iova_start, 0); + } } } -- 2.17.1