Received: by 2002:a25:6193:0:0:0:0:0 with SMTP id v141csp1027052ybb; Wed, 8 Apr 2020 14:58:58 -0700 (PDT) X-Google-Smtp-Source: APiQypLHWNIOvsPF141e9Dta/GiTdpAiP+pPBpB+JlZaIOcF6Z01roDKkW0gQ7WutntXR3DbCGVN X-Received: by 2002:aca:dbd6:: with SMTP id s205mr3941183oig.109.1586383137868; Wed, 08 Apr 2020 14:58:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1586383137; cv=none; d=google.com; s=arc-20160816; b=yKfGdxHa0fCsCHUXKlA7Wethpk/+CSTIfoIxntiHtwNfMF4ry7SuHrcoPzgTYcDbl0 dc2jDPJcUS/KphFeMH2j4vB3Zb50YHQQR1qwibkgGlUYwZqAB7brvizuzy/fUrMauMCb ArjWj9KkS3FZtKqkLy3MnS/Ew0ioH8flQxTv0JhY/6CKk4rcXYr8tCpm8j/q8e4rZ03V SBiOGzttm8O6cuB8f2aJRuEW4X0THH8DYOGl1RJ6F8MnGrroUnqvIU7CxHCczdlUGIrP DlvVKuHySbBEJpj69sxBbRXP5KKytY/V/XKGRrCzgxRriw/gz/oZJktT+XWXAt3emKNy JFQQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :message-id:in-reply-to:subject:cc:to:from:date:dkim-signature; bh=XrwqZbZ6JyVYdyuo7IDIjfmWjlFwWYqBg8MJXvuP7Jc=; b=X2S/PfSd42PpFdoiInwZNbifTHWiGw/ZIRh3y/5m1cXaFUs6xh1XYEWKqMRR0hrcS6 FW3EAp4Pb1ufU44uH7UIz6vo10dyb6HQRI8Z0wMK5skRmU1jJIXzxduTqufycWU9EYcc mvncQ0AD12p5JF3+pynXvu7cCiO+oEGeiZ078JGwCbBY+VICP5yaj6SxCYTrrzKZUhiK mFPmqSjuGFLUf5PZpU3msCMYPD7i2jZonsIy2UGWQgkwn7ziWIwPynFZRosnZ0OEPgtk 12bR9hYSPcJRsSoGZhKqhjG7QUPZ9w69XIIb6SBpWi4IPD+LADbPl8tN57aih8LIZpwH 3gDQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=A2jYLkpG; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a6si2351548otp.100.2020.04.08.14.58.45; Wed, 08 Apr 2020 14:58:57 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=A2jYLkpG; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730318AbgDHVVN (ORCPT + 99 others); Wed, 8 Apr 2020 17:21:13 -0400 Received: from mail-pl1-f195.google.com ([209.85.214.195]:41310 "EHLO mail-pl1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730241AbgDHVVJ (ORCPT ); Wed, 8 Apr 2020 17:21:09 -0400 Received: by mail-pl1-f195.google.com with SMTP id d24so2995319pll.8 for ; Wed, 08 Apr 2020 14:21:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:from:to:cc:subject:in-reply-to:message-id:references :user-agent:mime-version; bh=XrwqZbZ6JyVYdyuo7IDIjfmWjlFwWYqBg8MJXvuP7Jc=; b=A2jYLkpGa0TCVu3kNy7L56iAgQwz3sQ513YQzo//e/Wc3fAPFs6p7v+WNGTHIO3KeU BeluFw3ZxMv09dOUmZf7M7NBt6RjPcjCW02G3bQ/bxNGs+fhqdNmNWa9H/0AAgRfCWPi PADq4pdWtj8LIkrAmyp+PXKyyLrBC+NR7bSfsVUploFgg07Mtttnv1b591p7vqTUakpp AQhZdZJ64dKSx0hvbr3C1VPDQeF8DdzjllK6umv12yPbTurhEo3xLdVTmVYhlQucCPCt IfSSBRrhsaic5yUufnGm5LnQLzntolBb1LU9wxzWfYVDpaVZ7chXGrXrhFCsNYDMFXlk mVzw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:in-reply-to:message-id :references:user-agent:mime-version; bh=XrwqZbZ6JyVYdyuo7IDIjfmWjlFwWYqBg8MJXvuP7Jc=; b=lYudSpfoS8uSpuVvpBQYTMXxM08rMh1mZRIQm1kI8jfQsvCnpBXXJO1fS7KLaXjoJN Rm3GS40CN+VihkQm42ey4DqFtQuGNoEqz8WlJPcTCUbk4D5E9yQjw9+tahRGQwS1bR6b lGMLKdpu1uarp939nDo8I5oVcoM1tdmrF5gzyBxsG6bn6MVRk5RWffq8mdrvzdXoK44w KlbNgOmlGLjz1SU+pIi8GhyNt7dHq5ZC/pp4jL2s2BMEBXFxHnd65n9IuJ06OcEOPCRo TDgVsm/c21HrZxmyP9RTX/+WmWIZ/jaY60RRspcLAnzVMGhj7XIe65Yms0ka4v9x/hlT 75xA== X-Gm-Message-State: AGi0PuYpK4FEseWhSuJVYkIQ3S5lxntXcAOPLtQPxpW+cphV5FREyRMu NzLYlJ/foZ5DS3dTmGNcjEXYZw== X-Received: by 2002:a17:90a:3328:: with SMTP id m37mr7669217pjb.158.1586380868065; Wed, 08 Apr 2020 14:21:08 -0700 (PDT) Received: from [2620:15c:17:3:3a5:23a7:5e32:4598] ([2620:15c:17:3:3a5:23a7:5e32:4598]) by smtp.gmail.com with ESMTPSA id a185sm17750579pfa.27.2020.04.08.14.21.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 08 Apr 2020 14:21:07 -0700 (PDT) Date: Wed, 8 Apr 2020 14:21:06 -0700 (PDT) From: David Rientjes X-X-Sender: rientjes@chino.kir.corp.google.com To: Christoph Hellwig , Tom Lendacky cc: "Singh, Brijesh" , "Grimm, Jon" , Joerg Roedel , "linux-kernel@vger.kernel.org" , "iommu@lists.linux-foundation.org" Subject: [rfc v2 3/6] dma-pool: dynamically expanding atomic pools In-Reply-To: Message-ID: References: User-Agent: Alpine 2.21 (DEB 202 2017-01-01) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When an atomic pool becomes fully depleted because it is now relied upon for all non-blocking allocations through the DMA API, allow background expansion of each pool by a kworker. When an atomic pool has less than the default size of memory left, kick off a kworker to dynamically expand the pool in the background. The pool is doubled in size, up to MAX_ORDER-1. If memory cannot be allocated at the requested order, smaller allocation(s) are attempted. This allows the default size to be kept quite low when one or more of the atomic pools is not used. This also allows __dma_atomic_pool_init to return a pointer to the pool to make initialization cleaner. Also switch over some node ids to the more appropriate NUMA_NO_NODE. Signed-off-by: David Rientjes --- kernel/dma/pool.c | 120 +++++++++++++++++++++++++++++++--------------- 1 file changed, 82 insertions(+), 38 deletions(-) diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c index 9b806f5eded8..e14c5a2da734 100644 --- a/kernel/dma/pool.c +++ b/kernel/dma/pool.c @@ -11,13 +11,17 @@ #include #include #include +#include static struct gen_pool *atomic_pool_dma __ro_after_init; static struct gen_pool *atomic_pool_dma32 __ro_after_init; static struct gen_pool *atomic_pool_kernel __ro_after_init; #define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K -static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE; +static size_t atomic_pool_size = DEFAULT_DMA_COHERENT_POOL_SIZE; + +/* Dynamic background expansion when the atomic pool is near capacity */ +static struct work_struct atomic_pool_work; static int __init early_coherent_pool(char *p) { @@ -26,76 +30,114 @@ static int __init early_coherent_pool(char *p) } early_param("coherent_pool", early_coherent_pool); -static int __init __dma_atomic_pool_init(struct gen_pool **pool, - size_t pool_size, gfp_t gfp) +static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, + gfp_t gfp) { - const unsigned int order = get_order(pool_size); - const unsigned long nr_pages = pool_size >> PAGE_SHIFT; + unsigned int order; struct page *page; void *addr; - int ret; + int ret = -ENOMEM; + + /* Cannot allocate larger than MAX_ORDER-1 */ + order = min(get_order(pool_size), MAX_ORDER-1); + + do { + pool_size = 1 << (PAGE_SHIFT + order); - if (dev_get_cma_area(NULL)) - page = dma_alloc_from_contiguous(NULL, nr_pages, order, false); - else - page = alloc_pages(gfp, order); + if (dev_get_cma_area(NULL)) + page = dma_alloc_from_contiguous(NULL, 1 << order, + order, false); + else + page = alloc_pages(gfp, order); + } while (!page && order-- > 0); if (!page) goto out; arch_dma_prep_coherent(page, pool_size); - *pool = gen_pool_create(PAGE_SHIFT, -1); - if (!*pool) - goto free_page; - addr = dma_common_contiguous_remap(page, pool_size, pgprot_dmacoherent(PAGE_KERNEL), __builtin_return_address(0)); if (!addr) - goto destroy_genpool; + goto free_page; - ret = gen_pool_add_virt(*pool, (unsigned long)addr, page_to_phys(page), - pool_size, -1); + ret = gen_pool_add_virt(pool, (unsigned long)addr, page_to_phys(page), + pool_size, NUMA_NO_NODE); if (ret) goto remove_mapping; - gen_pool_set_algo(*pool, gen_pool_first_fit_order_align, NULL); - pr_info("DMA: preallocated %zu KiB %pGg pool for atomic allocations\n", - pool_size >> 10, &gfp); return 0; remove_mapping: dma_common_free_remap(addr, pool_size); -destroy_genpool: - gen_pool_destroy(*pool); - *pool = NULL; free_page: - if (!dma_release_from_contiguous(NULL, page, nr_pages)) + if (!dma_release_from_contiguous(NULL, page, 1 << order)) __free_pages(page, order); out: - pr_err("DMA: failed to allocate %zu KiB %pGg pool for atomic allocation\n", - pool_size >> 10, &gfp); - return -ENOMEM; + return ret; +} + +static void atomic_pool_resize(struct gen_pool *pool, gfp_t gfp) +{ + if (pool && gen_pool_avail(pool) < atomic_pool_size) + atomic_pool_expand(pool, gen_pool_size(pool), gfp); +} + +static void atomic_pool_work_fn(struct work_struct *work) +{ + if (IS_ENABLED(CONFIG_ZONE_DMA)) + atomic_pool_resize(atomic_pool_dma, GFP_DMA); + if (IS_ENABLED(CONFIG_ZONE_DMA32)) + atomic_pool_resize(atomic_pool_dma32, GFP_DMA32); + atomic_pool_resize(atomic_pool_kernel, GFP_KERNEL); +} + +static __init struct gen_pool *__dma_atomic_pool_init(size_t pool_size, + gfp_t gfp) +{ + struct gen_pool *pool; + int ret; + + pool = gen_pool_create(PAGE_SHIFT, NUMA_NO_NODE); + if (!pool) + return NULL; + + gen_pool_set_algo(pool, gen_pool_first_fit_order_align, NULL); + + ret = atomic_pool_expand(pool, pool_size, gfp); + if (ret) { + gen_pool_destroy(pool); + pr_err("DMA: failed to allocate %zu KiB %pGg pool for atomic allocation\n", + pool_size >> 10, &gfp); + return NULL; + } + + pr_info("DMA: preallocated %zu KiB %pGg pool for atomic allocations\n", + gen_pool_size(pool) >> 10, &gfp); + return pool; } static int __init dma_atomic_pool_init(void) { int ret = 0; - int err; - ret = __dma_atomic_pool_init(&atomic_pool_kernel, atomic_pool_size, - GFP_KERNEL); + INIT_WORK(&atomic_pool_work, atomic_pool_work_fn); + + atomic_pool_kernel = __dma_atomic_pool_init(atomic_pool_size, + GFP_KERNEL); + if (!atomic_pool_kernel) + ret = -ENOMEM; if (IS_ENABLED(CONFIG_ZONE_DMA)) { - err = __dma_atomic_pool_init(&atomic_pool_dma, - atomic_pool_size, GFP_DMA); - if (!ret && err) - ret = err; + atomic_pool_dma = __dma_atomic_pool_init(atomic_pool_size, + GFP_DMA); + if (!atomic_pool_dma) + ret = -ENOMEM; } if (IS_ENABLED(CONFIG_ZONE_DMA32)) { - err = __dma_atomic_pool_init(&atomic_pool_dma32, - atomic_pool_size, GFP_DMA32); - if (!ret && err) - ret = err; + atomic_pool_dma32 = __dma_atomic_pool_init(atomic_pool_size, + GFP_DMA32); + if (!atomic_pool_dma32) + ret = -ENOMEM; } return ret; } @@ -144,6 +186,8 @@ void *dma_alloc_from_pool(struct device *dev, size_t size, ptr = (void *)val; memset(ptr, 0, size); } + if (gen_pool_avail(pool) < atomic_pool_size) + schedule_work(&atomic_pool_work); return ptr; }