From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-183.mta0.migadu.com (out-183.mta0.migadu.com [91.218.175.183]) (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 C09C22931C2 for ; Wed, 15 Jul 2026 09:55:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.183 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784109333; cv=none; b=BgJ/jzWKyP2N7hjnRKn2pdVoi75wRcXROBuzJgJ/KLXPZUEQui4j+1aBoi5lgBhGa9Ff4ApB25QNO9UZhA6swoxtoo1+g2s9Ka/w8X4Q0RRS6+qMTWClG91HGMDu0JGiCNlzx5k2gTkROmy8ORsG5z7ceOY+V/pvIemiD7x9XE8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784109333; c=relaxed/simple; bh=/zbSn/Zl9cFgxxCr5OFQs4Cex03m1gys/c/f4LVoQ5w=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=JlPHTt6LDoWVlz0lnUM7Xa85O0ZzjEpbCE912ot49br7NcI2/dBbfPH+oheBBM0gJB6geTEyjW3+RUTqgBYEVNi5XoWhlA5Sf/i0KLPpkOuWcOdbfCSawI9mp6QL8+rjRf9IVR7fiPHXSKal8a99n2csC8Th5qBi//1uQMY0X8E= 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=N9uBXyDt; arc=none smtp.client-ip=91.218.175.183 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="N9uBXyDt" Message-ID: DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1784109329; 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=XvgKa/USJzi3aLKch9bAcPG3u928zva7NKYr9yMAqGg=; b=N9uBXyDthtR+jEdFl9U0hetMI4brBYNyW6zc//uXLZzMhDUvmX3HxDGgVjUdbTogV39lKg /EC1mUJq30/BWGreK/i/mLD39+6KfUjnyivaTN/j0s8+4/Skjm8fmKNfosGkZUr2Z8eTmJ olWf4AfppXooovoK7OeNuWtjHA7R1T0= Date: Wed, 15 Jul 2026 17:55:17 +0800 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Subject: Re: [PATCH] mm: shmem: make unused huge shrinker memcg aware To: Baolin Wang , hughd@google.com, akpm@linux-foundation.org, usama.arif@linux.dev Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, Qi Zheng References: <20260714031918.308-1-qi.zheng@linux.dev> <7624107f-6a2d-4959-b2ee-aa362a8972eb@linux.alibaba.com> X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. From: Qi Zheng In-Reply-To: <7624107f-6a2d-4959-b2ee-aa362a8972eb@linux.alibaba.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT Hi Baolin, On 7/15/26 5:37 PM, Baolin Wang wrote: > Hi Qi, > > On 7/14/26 11:19 AM, Qi Zheng wrote: >> From: Qi Zheng >> >> The shmem unused huge shrinker keeps a per-superblock list of inodes >> whose >> tail huge folio extends beyond i_size. Since that list is not memcg >> aware, >> reclaim triggered by one memcg can scan inodes from the whole superblock >> and split shmem huge folios charged to unrelated memcgs. >> >> Convert the shrink list to a memcg-aware list_lru. Queue each inode on >> the >> list_lru sublist matching the memcg and node of the current tail huge >> folio, so non-root memcg reclaim only walks candidates charged to the >> reclaiming memcg. Global reclaim, root memcg reclaim and shmem quota >> reclaim keep global semantics. >> >> The list_lru still tracks inodes while the actual split target is the >> current tail huge folio, so validate the folio memcg/node during scan. If >> the folio no longer matches the reclaim context or splitting cannot >> proceed, requeue the inode according to the current tail folio; if the >> inode is no longer shrinkable, drop the scan entry. >> >> This can be tested with the shrinker debugfs interface by allocating 32 >> tmpfs tail THPs in each of two memcgs, then scanning the sb-tmpfs >> shrinker >> with memcg A's cgroup id: >> >>                 before A scan        after A scan >>    base         A=64M, B=64M         A=0,  B=0 >>    patched      A=64M, B=64M         A=0,  B=64M >> >> Signed-off-by: Qi Zheng >> --- > > Thanks for your patch. This work has been on my TODO list for a while :) > > Overall it looks good. I'll take a closer look and run some tests. Thanks! > >> This patch is based on next-20260701 because it doesn't include this >> patch: >> >> https://lore.kernel.org/all/20260609123047.1948242-1- >> usama.arif@linux.dev/ >> >> Later on, Usama will consider moving this restriction down into the fs >> callback. >> >>   include/linux/shmem_fs.h |  14 +- >>   mm/shmem.c               | 379 ++++++++++++++++++++++++++++++--------- >>   2 files changed, 310 insertions(+), 83 deletions(-) >> >> diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h >> index e729b9b0e38d4..0b14de1e890a9 100644 >> --- a/include/linux/shmem_fs.h >> +++ b/include/linux/shmem_fs.h >> @@ -11,6 +11,7 @@ >>   #include >>   #include >>   #include >> +#include >>   struct swap_iocb; >> @@ -56,6 +57,13 @@ struct shmem_inode_info { >>       struct dquot __rcu    *i_dquot[MAXQUOTAS]; >>   #endif >>       struct inode        vfs_inode; >> + >> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE >> +    struct list_head    shrinklist_scan; > > Why introduce another list_head member? Why can't we reuse 'shrinklist' > in this structure? In other words, if we isolate this inode from > list_lru, then 'inode_info->shrinklist' can be reused to link it into > the temporary list, right? After list_lru isolation, the shrinker drops the list_lru lock and processes the inode on a local scan list. During that time, shmem faults can make the inode's current tail huge folio change, and shmem_unused_huge_add() may need to queue the same inode again on the active list_lru, possibly under a different memcg/node sublist. If we reused info->shrinklist for the temporary scan list, then while the inode is being scanned: 1. info->shrinklist would be non-empty because it is on the local scan list, so shmem_unused_huge_add() could not tell that the inode is no longer on the active list_lru. 2. Re-adding it to list_lru with the same list_head would corrupt the local scan list. 3. Skipping the add would lose the new current tail huge folio if the scan later drops the old scan entry instead of requeueing it. So isolation removes the inode from the active list_lru and leaves info->shrinklist empty. A concurrent fault can safely add the inode back to the active list_lru with the current folio's memcg/node, while the shrinker still owns the old scan entry through shrinklist_scan. The scan loop then detects that re-add and drops the stale scan entry, leaving the active entry for a later scan. > >> +    struct mem_cgroup    *shrinklist_memcg; >> +    int            shrinklist_nid; >> +    bool            shrinklist_isolated; > > Do we need an extra bool to indicate whether it's isolated? Can't we > just use 'list_empty(inode_info->shrinklist)'? I may have missed some > details. list_empty(info->shrinklist) cannot be used for this. That list node tracks active list_lru membership only. But you are right that the explicit bool is not necessary, we can use list_empty(&info->shrinklist_scan) instead. Thanks, Qi