From nobody Mon Feb 9 17:34:47 2026 Received: from mail-pg1-f178.google.com (mail-pg1-f178.google.com [209.85.215.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ACF0D346E6E for ; Wed, 28 Jan 2026 09:30:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769592659; cv=none; b=iP1kt7cvnBcgDAyH/lEY/8m8ZhdlO86lVWNig6mx4+QL4cgYUqhYTap2xehHqIQrr1j4DQK2lumfdSfP77jByV0HfZpk14mA3sEDR8u7HaGJS807B766DJdfijNrMKb1YBm7DCtHBBaxa8Dqpe2XWXhWNGR2pGYn3dMnu9uxBoE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769592659; c=relaxed/simple; bh=Er02vhxaEVbwJu/z/eFj3qEl2mARw7tjDYxAvy8TGt0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Dc/NKr5WG3MTO53KgydC1ExmitZCysUONqh5z77AWBQm7pgyLcdlViJ+lunzx0h1tgkv+hCdMsr6PMpP/yOF1GD0wxlYG3OFCnR2HtOoBs8BEZlV93csMJEAX5ExDbQg3Jmpkr+cZSoZ1oTgu3IA/sy6zomA75TfTQlfhka3suI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=kxbbyfk3; arc=none smtp.client-ip=209.85.215.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="kxbbyfk3" Received: by mail-pg1-f178.google.com with SMTP id 41be03b00d2f7-c551edc745eso2711966a12.2 for ; Wed, 28 Jan 2026 01:30:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1769592657; x=1770197457; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=FByi9ivqPJyIjI850sU//sSIfdwjIzLDbOJYWWeWKFE=; b=kxbbyfk3U2h5NtSM1yp6zuLtBLolKRyaYHfHjEt3ZaS883nqHQ2yiOsGxXn3lIc66o kh9VtxeGoB/T6SP83JwjZyuN3j1C1CaEU7CYVaW6VC3emNGgOfnuPK7sEWLOpHEEHhwa yt9d2exjYFOmzl9QvJIGifHbt4E1jPSLWKkRAypEdAVtVC9nMJ51/EDEFf1tkh+nId7V oukyMeWgfTVsUCgQWFSZXQk8k9CBQo2qAD+Yf8wbdsur7RlRGlVyAcxi1OjJ8ezv/xKN aW4BaYeOrBY8lmi1mcYhWWBcEfVSP1VXO33RXY30xAMKgtAzCJus/Qc94lTR0/w6SPmK FmsA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769592657; x=1770197457; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=FByi9ivqPJyIjI850sU//sSIfdwjIzLDbOJYWWeWKFE=; b=rfICE3zDD8LZ96xKqNmGTvRSN75TgQGJTu5NDU4cSdNj7Xc0yth8HNeoi1ow8e8MLD dIGWhtE1Umpn+EmcUKPCaqw74iSPjD5cYJ6Rqy3WnbzKp7Mr1My7nKCNlWIpAAjbyzll 7Yr2LTC9Y+EHXLNF+mumpi3U5rlpylVuKdv/WF9BwzKG2zBef3nQFnuA+YEh1lZgTnYq IUOoMXTWfrcLxsfYx+0xecQ/0CC6w3YKbmuN9XrX590cc+dvQYeQIFdkwFFouMA8b359 bG9KNHrPcltQjXD//matnpi0ZZyclGbQhZol0S0b2qBERBnA9I9LaMrH5AUo/qpycTgC Yo5Q== X-Forwarded-Encrypted: i=1; AJvYcCU/A6d60kB58zWQAaFCt5a/3nZ8evXYe9PXgvCA3DaIcg7kxcf5Lje4pvflHKRCgMeW5cFArnrueMzeMrw=@vger.kernel.org X-Gm-Message-State: AOJu0YxktJpIK7kLxnAVLonpTR0HsSFqKhuQWZJoWjBLqB9ONZ1zABQG GREtNWzCLfeqIyMaDcp0Kr4W61Q2/essPT+2GXteletTa879rCUJmdXafj4bMoK3fcM= X-Gm-Gg: AZuq6aIpIqBimlX0FjHk5fL4+L6/KPoHn5qh5vhj672QMFrsgUMzB7FUrS09I19TJ2a v6cqIdpia5SxnKXnYGqE1M1N96a4j7v4BF36O8ss0O6BChb7eCoI7y9TYXYoGy221Gsu1uxGl1d EEaxjlh1hSTF2RaOSog0YAMcN+OmkjCTW4o8GVc660OFUNs3qi09d2Kps0tKLi+JEca8TuiqPiD osokyqf7F0QTxz6sjV9GUB6pSyNPxi28iJWffjROOFEqEYhWx79GtpRZY4X/Wxi8xFI0/c67Q07 Nz9wLfwjLTx5QCzJ5rEr1VPvuQfwzisr1XBFgRjFpEnkFJsbs2nj7oWw8PhFcdsL1sAHlCJiZiL XC9b+KI1nrIUZjRI4CyQTfydJoOgAfMxN7dh2dCnZJMKLbMm5naz2k3Fy05gYujRn/wfvEpLlLC irzY7VGmgBh74H8rPxgXoKnLXGU0+Ca6P8s7qXIFNjD4S/At+qcApFV2TTsw== X-Received: by 2002:a17:90b:2c86:b0:32e:7340:a7f7 with SMTP id 98e67ed59e1d1-353feccb368mr3822825a91.2.1769592656953; Wed, 28 Jan 2026 01:30:56 -0800 (PST) Received: from [127.0.0.1] ([43.132.141.21]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3540f3eca6dsm1872235a91.15.2026.01.28.01.30.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Jan 2026 01:30:56 -0800 (PST) From: Kairui Song Date: Wed, 28 Jan 2026 17:28:31 +0800 Subject: [PATCH v2 07/12] mm, swap: mark bad slots in swap table directly 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-Transfer-Encoding: quoted-printable Message-Id: <20260128-swap-table-p3-v2-7-fe0b67ef0215@tencent.com> References: <20260128-swap-table-p3-v2-0-fe0b67ef0215@tencent.com> In-Reply-To: <20260128-swap-table-p3-v2-0-fe0b67ef0215@tencent.com> To: linux-mm@kvack.org Cc: Andrew Morton , Kemeng Shi , Nhat Pham , Baoquan He , Barry Song , Johannes Weiner , David Hildenbrand , Lorenzo Stoakes , Youngjun Park , linux-kernel@vger.kernel.org, Chris Li , Kairui Song X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1769592628; l=4470; i=kasong@tencent.com; s=kasong-sign-tencent; h=from:subject:message-id; bh=8m9COjsQHMkFcnP8SRLKraCOnV7wwqbxj9agW6bIMxQ=; b=PJ+2tKOVSzN+igBqvPYB4aflWKuvIjXVLzoOy7Sa6fTN51lteTQv078zHknrSO4i0Gbrf5zBc Y8yCq/5qPiBDOWGFjReAYZwOOSw8UlyCNYO2ncZR5mduSyDsLBD916v X-Developer-Key: i=kasong@tencent.com; a=ed25519; pk=kCdoBuwrYph+KrkJnrr7Sm1pwwhGDdZKcKrqiK8Y1mI= From: Kairui Song In preparing the deprecating swap_map, mark bad slots in the swap table too when setting SWAP_MAP_BAD in swap_map. Also, refine the swap table sanity check on freeing to adapt to the bad slots change. For swapoff, the bad slots count must match the cluster usage count, as nothing should touch them, and they contribute to the cluster usage count on swapon. For ordinary swap table freeing, the swap table of clusters with bad slots should never be freed since the cluster usage count never reaches zero. Signed-off-by: Kairui Song --- mm/swapfile.c | 56 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index df8b13eecab1..bdce2abd9135 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -454,16 +454,37 @@ static void swap_table_free(struct swap_table *table) swap_table_free_folio_rcu_cb); } =20 +/* + * Sanity check to ensure nothing leaked, and the specified range is empty. + * One special case is that bad slots can't be freed, so check the number = of + * bad slots for swapoff, and non-swapoff path must never free bad slots. + */ +static void swap_cluster_assert_empty(struct swap_cluster_info *ci, bool s= wapoff) +{ + unsigned int ci_off =3D 0, ci_end =3D SWAPFILE_CLUSTER; + unsigned long swp_tb; + int bad_slots =3D 0; + + if (!IS_ENABLED(CONFIG_DEBUG_VM) && !swapoff) + return; + + do { + swp_tb =3D __swap_table_get(ci, ci_off); + if (swp_tb_is_bad(swp_tb)) + bad_slots++; + else + WARN_ON_ONCE(!swp_tb_is_null(swp_tb)); + } while (++ci_off < ci_end); + + WARN_ON_ONCE(bad_slots !=3D (swapoff ? ci->count : 0)); +} + static void swap_cluster_free_table(struct swap_cluster_info *ci) { - unsigned int ci_off; struct swap_table *table; =20 /* Only empty cluster's table is allow to be freed */ lockdep_assert_held(&ci->lock); - VM_WARN_ON_ONCE(!cluster_is_empty(ci)); - for (ci_off =3D 0; ci_off < SWAPFILE_CLUSTER; ci_off++) - VM_WARN_ON_ONCE(!swp_tb_is_null(__swap_table_get(ci, ci_off))); table =3D (void *)rcu_dereference_protected(ci->table, true); rcu_assign_pointer(ci->table, NULL); =20 @@ -567,6 +588,7 @@ static void swap_cluster_schedule_discard(struct swap_i= nfo_struct *si, =20 static void __free_cluster(struct swap_info_struct *si, struct swap_cluste= r_info *ci) { + swap_cluster_assert_empty(ci, false); swap_cluster_free_table(ci); move_cluster(si, ci, &si->free_clusters, CLUSTER_FLAG_FREE); ci->order =3D 0; @@ -747,9 +769,11 @@ static int swap_cluster_setup_bad_slot(struct swap_inf= o_struct *si, struct swap_cluster_info *cluster_info, unsigned int offset, bool mask) { + unsigned int ci_off =3D offset % SWAPFILE_CLUSTER; unsigned long idx =3D offset / SWAPFILE_CLUSTER; - struct swap_table *table; struct swap_cluster_info *ci; + struct swap_table *table; + int ret =3D 0; =20 /* si->max may got shrunk by swap swap_activate() */ if (offset >=3D si->max && !mask) { @@ -767,13 +791,7 @@ static int swap_cluster_setup_bad_slot(struct swap_inf= o_struct *si, pr_warn("Empty swap-file\n"); return -EINVAL; } - /* Check for duplicated bad swap slots. */ - if (si->swap_map[offset]) { - pr_warn("Duplicated bad slot offset %d\n", offset); - return -EINVAL; - } =20 - si->swap_map[offset] =3D SWAP_MAP_BAD; ci =3D cluster_info + idx; if (!ci->table) { table =3D swap_table_alloc(GFP_KERNEL); @@ -781,13 +799,21 @@ static int swap_cluster_setup_bad_slot(struct swap_in= fo_struct *si, return -ENOMEM; rcu_assign_pointer(ci->table, table); } - - ci->count++; + spin_lock(&ci->lock); + /* Check for duplicated bad swap slots. */ + if (__swap_table_xchg(ci, ci_off, SWP_TB_BAD) !=3D SWP_TB_NULL) { + pr_warn("Duplicated bad slot offset %d\n", offset); + ret =3D -EINVAL; + } else { + si->swap_map[offset] =3D SWAP_MAP_BAD; + ci->count++; + } + spin_unlock(&ci->lock); =20 WARN_ON(ci->count > SWAPFILE_CLUSTER); WARN_ON(ci->flags); =20 - return 0; + return ret; } =20 /* @@ -2743,7 +2769,7 @@ static void free_swap_cluster_info(struct swap_cluste= r_info *cluster_info, /* Cluster with bad marks count will have a remaining table */ spin_lock(&ci->lock); if (rcu_dereference_protected(ci->table, true)) { - ci->count =3D 0; + swap_cluster_assert_empty(ci, true); swap_cluster_free_table(ci); } spin_unlock(&ci->lock); --=20 2.52.0