From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-178.mta0.migadu.com (out-178.mta0.migadu.com [91.218.175.178]) (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 1503F34A794 for ; Tue, 21 Jul 2026 08:06:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.178 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784621205; cv=none; b=V2Q6ei+WR2ra5QJMDIxDCGFW/gp4IVrb5zaPeR+t/HaZbC7wSovWNFBsjKEoQ/66EE05M4jE2z7WEgrQLiBWf66qHNWz7bkInh6tf0lzQiYI/gpCfrcE33yQEo/ceZZ9FZcCRF1+/Ah8Ohk8iv8dci+MH2ngvF9Y/09REzUrD6Q= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784621205; c=relaxed/simple; bh=mvvIHAFWrYaOO9KvkD0iBTbCI2ay0XnAIWzMslBUMzA=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=MaLtfSsUoep1vzo4UUWuYKTNwIVhJc5e4xU0qLoLv5n+qqH0nPNoSQMoJkDKPWXxg92QxPE541IJBEwcrD+GdxqalRhJE/LHJtH0VfX3NsaIUtjnNpJKBX56DmJq74Oj0dnnoyWfwX1mjZ+ZTdkYMiKWuWPGzu9waa6ZIEY3kxk= 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=GoXxF9gL; arc=none smtp.client-ip=91.218.175.178 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="GoXxF9gL" Date: Tue, 21 Jul 2026 16:06:29 +0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1784621199; 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=YRC91WJZB8K86VbjtUS5rd8+YdjblueKOYRzcZP+nsE=; b=GoXxF9gLCWOZ154SIxCP7kilRCqGxaRA7Q2wYzfIT/kdR9Lh1rosaSxTn8PZx5kF15XCys MPvedDbt5SO/WrWkissscNc5BdndpOvP8zvbqY1rj/3dgtn7tag1ZzFxXz4Zf5CDos2kSr lIxAWyPrR5ammgU5UCOV2LQYBWgg3AE= X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. From: Baoquan He To: Nhat Pham Cc: Chris Li , linux-mm@kvack.org, akpm@linux-foundation.org, kasong@tencent.com, shikemeng@huaweicloud.com, baohua@kernel.org, youngjun.park@lge.com, hannes@cmpxchg.org, yosry@kernel.org, chengming.zhou@linux.dev, linux-kernel@vger.kernel.org Subject: Re: [RFC PATCH 00/10] mm/swap: ghost swapfile with backend switching via Redirect entries Message-ID: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: X-Migadu-Flow: FLOW_OUT On 07/17/26 at 09:02am, Nhat Pham wrote: > On Fri, Jul 17, 2026 at 7:27 AM Baoquan He wrote: > > > > On 07/16/26 at 09:49am, Nhat Pham wrote: > > > > Thanks for the thoughtful reply and the very constructive proposal. > > Your suggestion about moving forward in small, incremental steps in > > last mail is really appealing — I think that's the right way to make > > progress on this. I need a little time to think it through more > > carefully before giving you a proper response. Will get back to you > > soon. > > Yeah let me know what you think. I'm planning to send out v3 with some > more cleanups and fixes, but I'm happy to hear what you and Chris > wants to make it as useful as possible for everyone. Hi Nhat, I've thought about it more carefully. Here's what I think the path forward could look like. I'll try to lay it out from the bottom up. 1. Data structure Instead of introducing a separate swap_cluster_info_dynamic wrapper, I'd prefer to add a per-slot backend pointer array directly into struct swap_cluster_info: struct swap_cluster_info { ... #ifdef CONFIG_ZSWAP atomic_long_t *vs_pointer; /* or xs_pointer — per-slot backend pointers */ #endif struct list_head list; }; This is allocated together with or alongside the swap table when the cluster is first used. No wrapper struct, no new ->cluster_info pointer type change — just one extra field that is NULL for clusters that don't need it. The name is bike-sheddable: vs_pointer (virtual-space pointer) or xs_pointer (cross-space pointer), xs_table (xswap extension table), aux_table (auxiliary table), priv_table (private data table), slot_priv (per-slot private data) or s_ext (slot extension). The point is that it stores a pointer to the backend owner of each slot — initially just struct zswap_entry *, eventually extensible to other backend types. I prefer to name it ext_table, but we have had extend_table. My second favorite option is aux_table. What's your choice? 2. Eliminate the zswap xarray Once vs_pointer is in place, zswap can store and load entries through vs_pointer[ci_off] instead of xa_store/xa_load on the per-device zswap xarray. The cluster lock protects the access. This is exactly the same idea as your virtual_table, just placed directly in swap_cluster_info rather than in a wrapper. The benefit: zswap_swapon and zswap_swapoff become no-ops (no global xarray to allocate or tear down). The per-cluster allocation is lazy — only clusters that actually see a zswap store allocate the array. 3. First step for ghost swap / virtual swap: dynamic growth and shrink, no writeback yet I think we agree that the first landing should be narrow in scope: - A virtual swap device that decouples PTE swap entries from physical backing. - Backed only by zswap (and zero pages) initially. - No writeback to physical swap. - Dynamic growth and shrink of the cluster space. For the dynamic cluster management, I'd like to try a lazy vmalloc approach: allocate the cluster_info array as a vmalloc region, and use vm_area_map_pages() to map newly populated clusters on demand. Growth is automatic via page faults; shrink means reclaiming the physical pages backing freed clusters. The vmalloc approach has O(1) lookup (simple array index), which matters on the swapout hot path. The trade-off is that shrink is coarser than xarray-based management (we can't easily unmap an individual cluster from the middle of the vmalloc region). But for the initial landing where swap usage tends to be ratchet-like, I think this is a reasonable trade-off. We can always switch to xarray later if shrink granularity becomes a real issue. 4. Writeback and rmap as follow-up Once the basic virtual swap device is upstream, we add writeback support: - When zswap store fails, fall back to allocating a physical swap slot and writing out. - The vs_pointer entry is updated to point to the physical slot (tagged to distinguish from a zswap_entry pointer). - rmap for physical -> virtual reverse lookup, needed for swapoff and physical slot reclaim. This is a natural extension: the vs_pointer is already per-slot, so adding a new backend type is a tag-bit change, not a rewrite. 5. Longer-term: swap tiering Looking further ahead, the per-slot pointer can also serve as the basis for a swap tiering model. Imagine a memcg with multiple tiers: ghost/virtual swap at the top, then pmem, then SSD, then HDD. Swapout goes to the top tier first; when that fills, data cascades down to the next tier. Each swap device only needs to know about the device directly below it — a simple "push down" interface. This is a longer-term vision, but having a uniform per-slot backend pointer from the start keeps the door open without painting us into a corner. 6. Naming We have three names floating around: "ghost swap", "virtual swap", and Chris suggested "xswap". We're going to be talking about this thing a lot, and having a single agreed-upon name would help avoid confusion in discussions, commit messages, and documentation. I don't have strong feelings about which one — but I'd like us to settle on something everyone can live with. 7. How to swapon a ghost / virtual swap device There are several approaches on the table right now: a) A sparse file created via truncate (Chris's approach): a swap file that looks large (e.g. 1GiB) but only has one real backing page. Works with the existing swapon syscall, but the sparse file has to live somewhere and the filesystem interaction is a bit of a hack. b) A boot-time, always-present device (your VSS approach): the vswap device is created unconditionally at late_initcall when CONFIG_VSWAP=y. No userspace action needed, but no runtime control either — you can't create or destroy it, and you can't have per-memcg or per-workload virtual swap spaces. c) A swapon flag: something like SWAP_FLAG_VIRTUAL or SWAP_FLAG_GHOST passed to swapon(2), which tells the kernel to treat the swap device as a ghost device with no backing storage. d) A dedicated sysfs / debugfs knob: create and size the ghost swap device at runtime via a file under /sys/kernel/mm/swap/. e) Something I'm missing? Each has trade-offs between flexibility, simplicity, and the existing swap management model. I'd like to hear what you and Chris think — especially whether the boot-time-only nature of the current VSS design is a deliberate simplification or something you'd be open to revisiting. Curious to hear what you think — especially if you see any structural issues with putting vs_pointer directly in swap_cluster_info rather than in a wrapper. If the wrapper is important for your v3 design, I'd like to understand the rationale better. Thanks, Baoquan