From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-186.mta0.migadu.com (out-186.mta0.migadu.com [91.218.175.186]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9701D39B4BB for ; Wed, 17 Jun 2026 08:57:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.186 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781686670; cv=none; b=llxFGU1EkAWPGoSAnMiCiNyESBbK4yaM2m/VmkzhQmiovHPVehNSGwwKmPEVOK/vhuEdJ8qKAZO0De1qaMDJbEdyDsqpmsLQHf4RdM9BdQPu4/RcoinpyST2Rv7zXlJ+nrgivVmXe+znfXh6QLjBsl2PSE5MHx0eklpak8ZwR+Y= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781686670; c=relaxed/simple; bh=LyC5v+WU129tl8q+GhrY3khPEfCHD/6kK6dyB/PNFtM=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=aIyA2/fX7KjeqRIpcXXoXgHWlLiBt1aDs2rZtfz2IX4p0FvxXihwESOGsxbU7D0JqYESPIlVtFXyNxXWT6vpvfvQT9e32TNLd6vb4oC98ZgnCGOmD1/JSxy7GX7C2lukVJ5xCpPZibkhgYRVqUlvAI9h7hNK9ctWl5h5aV0sSJs= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=G6zDIISx; arc=none smtp.client-ip=91.218.175.186 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="G6zDIISx" Message-ID: DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1781686666; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LJv33QYNn3uul9I11VO5bijTdE4dZbcs1/oX8cvoHKE=; b=G6zDIISxunkBVC1of9TkL8OfBK4o7OBby5JNOZDMEgIOCcKY7o0KinIEcyGmZSIhVa+bC0 AFCmsquCrexm2aEivFGneGwasore4AZAdRNchMCQtYo3oBwmSIq1swY7HIO7L3+BfdPt5B yR43tg3gf/O3Sh6pe2dHrhWaYepnBik= Date: Wed, 17 Jun 2026 16:56:56 +0800 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Subject: Re: [PATCH v3 3/3] mm/percpu: Avoid IO/FS reclaim in backing allocations To: Dennis Zhou Cc: Andrew Morton , Uladzislau Rezki , Tejun Heo , Christoph Lameter , Vlastimil Babka , Michal Hocko , muchun.song@linux.dev, linux-mm@kvack.org, linux-kernel@vger.kernel.org, Kaitao Cheng References: <20260612022648.13008-1-kaitao.cheng@linux.dev> <20260612022648.13008-4-kaitao.cheng@linux.dev> X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. From: Kaitao Cheng In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT 在 2026/6/17 14:53, Dennis Zhou 写道: > On Fri, Jun 12, 2026 at 10:26:48AM +0800, Kaitao Cheng wrote: >> From: Kaitao Cheng >> >> Commit 9a5b183941b5 ("mm, percpu: do not consider sleepable >> allocations atomic") allows sleepable GFP_NOIO and GFP_NOFS percpu >> allocations to take pcpu_alloc_mutex. This avoids premature allocation >> failures, but it also makes the mutex visible to callers from constrained >> IO/FS contexts. >> >> Thread A calls pcpu_alloc_noprof() with GFP_KERNEL and takes >> pcpu_alloc_mutex. Since the internal allocation is not constrained by >> NOFS, it may enter FS reclaim while still holding pcpu_alloc_mutex, >> creating a dependency like: pcpu_alloc_mutex -> fs_reclaim -> FS lock >> >> At the same time, Thread B may already hold an FS lock and then call >> pcpu_alloc_noprof() with GFP_NOFS. It will try to acquire >> pcpu_alloc_mutex and block, creating the reverse dependency: >> FS lock -> pcpu_alloc_mutex >> >> This can still form a potential deadlock cycle. >> >> Avoid the dependency by restricting percpu backing allocations to GFP_NOIO. >> The public allocation still uses the caller's GFP context to decide whether >> it may block, but the internal memory allocations performed while >> pcpu_alloc_mutex is held cannot recurse into IO or FS reclaim. >> >> Fixes: 9a5b183941b5 ("mm, percpu: do not consider sleepable allocations atomic") >> Signed-off-by: Kaitao Cheng >> --- >> mm/percpu.c | 16 +++++++++++----- >> 1 file changed, 11 insertions(+), 5 deletions(-) >> >> diff --git a/mm/percpu.c b/mm/percpu.c >> index 4d89965cba16..47824061a701 100644 >> --- a/mm/percpu.c >> +++ b/mm/percpu.c >> @@ -1726,9 +1726,9 @@ static void pcpu_alloc_tag_free_hook(struct pcpu_chunk *chunk, int off, size_t s >> * @gfp: allocation flags >> * >> * Allocate percpu area of @size bytes aligned at @align. If @gfp doesn't >> - * contain %GFP_KERNEL, the allocation is atomic. If @gfp has __GFP_NOWARN >> - * then no warning will be triggered on invalid or failed allocation >> - * requests. >> + * allow blocking, the allocation is atomic. If @gfp has __GFP_NOFAIL, backing >> + * allocation failures are retried. If @gfp has __GFP_NOWARN then no warning >> + * will be triggered on invalid or failed allocation requests. >> * >> * RETURNS: >> * Percpu pointer to the allocated area on success, NULL on failure. >> @@ -1749,8 +1749,14 @@ void __percpu *pcpu_alloc_noprof(size_t size, size_t align, bool reserved, >> size_t bits, bit_align; >> >> gfp = current_gfp_context(gfp); >> - /* whitelisted flags that can be passed to the backing allocators */ >> - pcpu_gfp = gfp & (GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN); >> + /* >> + * Allowlisted flags that can be passed to the backing allocators. >> + * Backing allocations under pcpu_alloc_mutex must not recurse into >> + * IO/FS reclaim. Otherwise a GFP_KERNEL caller holding the mutex can >> + * block on reclaim while a GFP_NOIO/NOFS caller holding an IO/FS lock >> + * waits for the same mutex. >> + */ >> + pcpu_gfp = gfp & (GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOFAIL); >> is_atomic = !gfpflags_allow_blocking(gfp); >> do_warn = !(gfp & __GFP_NOWARN); >> > > I think GFP_KERNEL -> GFP_NOIO makes sense. It breaks the cycle. > > For __GFP_NOFAIL, I think my concern is that a chunk can be quite large > and might need numerous pages. If we allow __GFP_NOFAIL, then we could > potentially churn and stall out other allocations for quite some time > while GFP_NOIO tries to reclaim without access to fs or io paths. __GFP_NOFAIL is actually unnecessary here. The main reason is that, for now, I have not found any in-kernel callers that pass __GFP_NOFAIL to pcpu_alloc_noprof() or its wrapper functions. The reason I added __GFP_NOFAIL was to address the issue reported by sashiko, and I provided a detailed clarification in the link below. https://lore.kernel.org/all/3de3a89b-92f0-4cd2-9f41-8e853eae4e78@linux.dev/ We should probably revert the current patch back to the v2 version, and then add some comments explaining why pcpu_alloc_noprof() must not be passed the __GFP_NOFAIL flag, as suggested by Andrew Morton. -- Thanks Kaitao Cheng