From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-179.mta1.migadu.com (out-179.mta1.migadu.com [95.215.58.179]) (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 D2BC32DD5E2 for ; Tue, 7 Jul 2026 08:26:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.179 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783412803; cv=none; b=bTixgIf5uEZFQhKvazbA/pIRtLXdSE1vPXay/3C93zR+qHGraMdztDIwb/zGoi1t/113tFPPyHlOkHuZfGWm1RaeB1AI0SFt4nceHveM6nMF3ufineFRiA5z3zOfiGRi5Jfo5iiON+wsS8M4UorvkgojbRX2RdEa3gCA7FUhRck= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783412803; c=relaxed/simple; bh=dvpDFRwcOtH8UFMaE3uBrqlb1thXMIQ5t+uElsQHzso=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-type; b=a6mSGLgdF840Xw3gwkhhIWeWigSaLEDCxzeV2Ky0RlBNI1JDRnDPeAVwR/dtRKagHXxJegFChZH3XY0feha43B2MPQflH1pSvcSqYrimzMb7cvUc+Y1kTsocaskDqU0gcYV4mtwo9ALRrv5BvJLDJU0UIiNxUOMtFkLRslg4kUI= 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=Zwj3pO6E; arc=none smtp.client-ip=95.215.58.179 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="Zwj3pO6E" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1783412798; 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=d9ihXWGN4Yr26k3bShB4RRwMn22NraC0vuJJuiUB3t4=; b=Zwj3pO6ERe7pxf8BJHHpSLN7EX17lLaBwNvIm5wPMvZOx48TG1itaDT9VgsUm7xX0lGIBv X7nKTXi6MeOMzektSfFsFZwnT30UGhscKw5W6qHu9sdyWml3Z2VmXfsYjLxeG6153VBl3n ktyO7czbd0T8RNnVtC4DjcAHZ7afvic= From: Baoquan He To: linux-mm@kvack.org Cc: akpm@linux-foundation.org, chrisl@kernel.org, kasong@tencent.com, shikemeng@huaweicloud.com, nphamcs@gmail.com, baohua@kernel.org, youngjun.park@lge.com, hannes@cmpxchg.org, yosry@kernel.org, chengming.zhou@linux.dev, linux-kernel@vger.kernel.org, Baoquan He Subject: [RFC PATCH 02/10] mm/swap_table: add Redirect entry encoding for ghost swap backend switching Date: Tue, 7 Jul 2026 16:26:04 +0800 Message-ID: <20260707082614.95030-3-baoquan.he@linux.dev> In-Reply-To: <20260707082614.95030-1-baoquan.he@linux.dev> References: <20260707082614.95030-1-baoquan.he@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-type: text/plain Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT Introduce SWP_TB_REDIRECT_MARK (0b101) as a new swap table entry type that stores a physical swp_entry_t directly. This allows a ghost swap slot to redirect to a physical swap slot after zswap writeback. The swp_entry_t has its low 12 bits clear (page-aligned offset), so the 3-bit mark is ORed directly into the value without shifting and without losing any type or offset bits. Add inline helpers: - swp_tb_is_redirect(): type check - swp_entry_to_redirect(): encode a swp_entry_t as a Redirect entry - redirect_to_swp_entry(): decode a Redirect entry back to swp_entry_t Update the swap table entry type documentation to include the new Redirect type. Signed-off-by: Baoquan He --- mm/swap_table.h | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/mm/swap_table.h b/mm/swap_table.h index 6318bf8aa76b..5a971152cf23 100644 --- a/mm/swap_table.h +++ b/mm/swap_table.h @@ -29,6 +29,7 @@ struct swap_memcg_table { * Shadow: |SWAP_COUNT|Z|---- SHADOW_VAL ---|1| - Swapped out slot * PFN: |SWAP_COUNT|Z|------ PFN -------|10| - Cached slot * Pointer: |----------- Pointer ----------|100| - Zswap compressed entry + * Redirect: |------- swp_entry_t.val ------|101| - Redirect to phys swap * Bad: |------------- 1 -------------|1000| - Bad slot * * COUNT is `SWP_TB_COUNT_BITS` long, Z is the `SWP_TB_ZERO_FLAG` bit, @@ -55,6 +56,11 @@ struct swap_memcg_table { * all upper bits. `0b100` is used as the marker because zswap_entry * pointers are at least 8-byte aligned, leaving the lower three bits free. * + * - Redirect: Stores a physical swp_entry_t directly, ending with `0b101`. + * Used by ghost swapfiles to redirect a virtual slot to a physical swap + * slot after zswap writeback. swp_entry_t has bits 0-11 clear (page-aligned + * offset), so the 3-bit mark is ORed directly into the value without shifting. + * * - Bad: Swap slot is reserved, protects swap header or holes on swap devices. */ @@ -83,6 +89,15 @@ struct swap_memcg_table { /* Pointer: zswap_entry pointer stored directly, ends with 0b100 */ #define SWP_TB_POINTER_MARK 0b100UL +/* + * Redirect: stores a physical swp_entry_t directly, ends with 0b101. + * Used by ghost swapfiles to redirect a virtual slot to a physical + * swap slot after writeback. swp_entry_t has its low 12 bits clear + * (page-aligned offset), so we can OR the 3-bit mark directly into + * the entry value without shifting and without losing type bits. + */ +#define SWP_TB_REDIRECT_MARK 0b101UL + /* Bad slot: ends with 0b1000 and rests of bits are all 1 */ #define SWP_TB_BAD ((~0UL) << 3) @@ -176,6 +191,11 @@ static inline bool swp_tb_is_pointer(unsigned long swp_tb) return (swp_tb & (BIT(3) - 1)) == SWP_TB_POINTER_MARK; } +static inline bool swp_tb_is_redirect(unsigned long swp_tb) +{ + return (swp_tb & (BIT(3) - 1)) == SWP_TB_REDIRECT_MARK; +} + static inline bool swp_tb_is_countable(unsigned long swp_tb) { return (swp_tb_is_shadow(swp_tb) || swp_tb_is_folio(swp_tb) || @@ -215,6 +235,24 @@ static inline void *swp_tb_to_pointer(unsigned long swp_tb) return (void *)(swp_tb & ~((unsigned long)(BIT(3) - 1))); } +/* + * Redirect encoding: swp_entry_t is stored directly, with the 3-bit + * mark ORed into the low bits. swp_entry_t.val has bits 0-11 clear + * (page-aligned offset), so no shifting is needed and no type bits + * are lost. + */ +static inline unsigned long swp_entry_to_redirect(swp_entry_t entry) +{ + VM_WARN_ON(entry.val & (BIT(3) - 1)); + return entry.val | SWP_TB_REDIRECT_MARK; +} + +static inline swp_entry_t redirect_to_swp_entry(unsigned long swp_tb) +{ + VM_WARN_ON(!swp_tb_is_redirect(swp_tb)); + return (swp_entry_t){ .val = swp_tb & ~((unsigned long)(BIT(3) - 1)) }; +} + static inline unsigned char __swp_tb_get_count(unsigned long swp_tb) { VM_WARN_ON(!swp_tb_is_countable(swp_tb)); -- 2.54.0