From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 CA8E730E825 for ; Thu, 19 Feb 2026 06:46:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771483562; cv=none; b=q80Fp3wuB5kDH3a0dCQ0KoIF0rqtDzYdELNBqxWNKjNgBr0TmZquE2yUy3pQVdAoL3mvixVLidG/h40Lm6bUBmeKck9jh2552rAegYdwqksEJZmO4iROqx6fpP7YS6RlXRQt+2yws9uKm/sG4HdMxsrieGds6z+lCGTl5spden8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771483562; c=relaxed/simple; bh=exIFoUQ7OlM/XQWxN/LJt7p9eZkh9S8E8n3kDGdCPhk=; h=MIME-Version:References:In-Reply-To:From:Date:Message-ID:Subject: To:Cc:Content-Type; b=RLjld4tYMzw/d/4osd/51hDSQ+LlNtfJqRkkGxxAme586xbwjPTd61ycRaC+FPmVPj9MnByhQVi7xd/Wv6jFbJ6kNKHv0jpDJVGYu7HoWbLYFOvkM58HJjVavFyryRghY1S+GKUyq4FzYhPuY+jPvLUYT4qagC/2aqWzc8h82As= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=V996QwKw; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="V996QwKw" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4A98AC19424 for ; Thu, 19 Feb 2026 06:46:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1771483562; bh=exIFoUQ7OlM/XQWxN/LJt7p9eZkh9S8E8n3kDGdCPhk=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=V996QwKwvgULtkC2UEPdJ+d5fbkPvgRmmARJ6z/kriwjbcyn1va1LdFBs4N9Y44cq gcwEkVG5XbCnv06VrtGVErnEab3S8bkqbrPwexH1j99co/Wt1G6HWkzjq9aIj26a5Y b7/IuYlenbAioKxk+j7DafCu5SxsxoIlJ8fbOZ7THk51u8T5ZCh78KbxAbu0QiXxdy cu64HEnGe0qUgrNArop51G2JulnZBwSaGyR2OnN3lh1jFeY+6BqPxr93kl5jkymMEb VfJ0jlX5dfXHUg+HXa9EDNMAHGdyCsoAsCZ5Db0CaalKzZUkMnKEzvYrPuOIgNcyHD M0HmD+CEVFM0w== Received: by mail-yx1-f44.google.com with SMTP id 956f58d0204a3-64ae5f0777dso428693d50.3 for ; Wed, 18 Feb 2026 22:46:02 -0800 (PST) X-Forwarded-Encrypted: i=1; AJvYcCWSRLdi6JpMtSHf9QOpHjl75Y2nSjDiiG/YkslDvcXoqBckKgHnX72SVTM0kXrqpqE673kdCu5d/H4fe9A=@vger.kernel.org X-Gm-Message-State: AOJu0YwXZjkGGjk1aW0MftiywIFKCEOtIbgG2mt85P76y+1dvaRtxBjS HNXrg7rb7BnhU37vjlTD5sfmAPsQqYmNjx1dQKPTASG2XPNbl3MudDsAqQAUTC13xeSIMbYFc84 V/QGADzoYpDK/8okRhgbp1Ztwq16klWdcytBfVbKkcA== X-Received: by 2002:a05:690e:140f:b0:645:5d39:2549 with SMTP id 956f58d0204a3-64c55587d97mr2839068d50.21.1771483561406; Wed, 18 Feb 2026 22:46:01 -0800 (PST) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 References: <20260218-swap-table-p3-v3-0-f4e34be021a7@tencent.com> <20260218-swap-table-p3-v3-2-f4e34be021a7@tencent.com> In-Reply-To: <20260218-swap-table-p3-v3-2-f4e34be021a7@tencent.com> From: Chris Li Date: Wed, 18 Feb 2026 22:45:50 -0800 X-Gmail-Original-Message-ID: X-Gm-Features: AZwV_Qi0brKcxdkGgvqo79TUDmPiyuvEqCu2daUYDg-eAK2ytxQ13PDGtRCXWYg Message-ID: Subject: Re: [PATCH v3 02/12] mm, swap: clean up swapon process and locking To: kasong@tencent.com Cc: linux-mm@kvack.org, Andrew Morton , Kemeng Shi , Nhat Pham , Baoquan He , Barry Song , Johannes Weiner , David Hildenbrand , Lorenzo Stoakes , Youngjun Park , linux-kernel@vger.kernel.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Acked-by: Chris Li On Tue, Feb 17, 2026 at 12:06=E2=80=AFPM Kairui Song via B4 Relay wrote: > > From: Kairui Song > > Slightly clean up the swapon process. Add comments about what swap_lock > protects, introduce and rename helpers that wrap swap_map and > cluster_info setup, and do it outside of the swap_lock lock. > > This lock protection is not needed for swap_map and cluster_info setup > because all swap users must either hold the percpu ref or hold a stable > allocated swap entry (e.g., locking a folio in the swap cache) before > accessing. So before the swap device is exposed by enable_swap_info, > nothing would use the swap device's map or cluster. > > So we are safe to allocate and set up swap data freely first, then > expose the swap device and set the SWP_WRITEOK flag. > > Signed-off-by: Kairui Song > --- > mm/swapfile.c | 87 ++++++++++++++++++++++++++++++++---------------------= ------ > 1 file changed, 48 insertions(+), 39 deletions(-) > > diff --git a/mm/swapfile.c b/mm/swapfile.c > index 25dfe992538d..8fc35b316ade 100644 > --- a/mm/swapfile.c > +++ b/mm/swapfile.c > @@ -65,6 +65,13 @@ static void move_cluster(struct swap_info_struct *si, > struct swap_cluster_info *ci, struct list_head *= list, > enum swap_cluster_flags new_flags); > > +/* > + * Protects the swap_info array, and the SWP_USED flag. swap_info contai= ns > + * lazily allocated & freed swap device info struts, and SWP_USED indica= tes Is "struts" a typo for "struct"? Chris > + * which device is used, ~SWP_USED devices and can be reused. > + * > + * Also protects swap_active_head total_swap_pages, and the SWP_WRITEOK = flag. > + */ > static DEFINE_SPINLOCK(swap_lock); > static unsigned int nr_swapfiles; > atomic_long_t nr_swap_pages; > @@ -2657,8 +2664,6 @@ static int setup_swap_extents(struct swap_info_stru= ct *sis, > } > > static void setup_swap_info(struct swap_info_struct *si, int prio, > - unsigned char *swap_map, > - struct swap_cluster_info *cluster_info, > unsigned long *zeromap) > { > si->prio =3D prio; > @@ -2668,8 +2673,6 @@ static void setup_swap_info(struct swap_info_struct= *si, int prio, > */ > si->list.prio =3D -si->prio; > si->avail_list.prio =3D -si->prio; > - si->swap_map =3D swap_map; > - si->cluster_info =3D cluster_info; > si->zeromap =3D zeromap; > } > > @@ -2687,13 +2690,11 @@ static void _enable_swap_info(struct swap_info_st= ruct *si) > } > > static void enable_swap_info(struct swap_info_struct *si, int prio, > - unsigned char *swap_map, > - struct swap_cluster_info *cluster_info, > - unsigned long *zeromap) > + unsigned long *zeromap) > { > spin_lock(&swap_lock); > spin_lock(&si->lock); > - setup_swap_info(si, prio, swap_map, cluster_info, zeromap); > + setup_swap_info(si, prio, zeromap); > spin_unlock(&si->lock); > spin_unlock(&swap_lock); > /* > @@ -2711,7 +2712,7 @@ static void reinsert_swap_info(struct swap_info_str= uct *si) > { > spin_lock(&swap_lock); > spin_lock(&si->lock); > - setup_swap_info(si, si->prio, si->swap_map, si->cluster_info, si-= >zeromap); > + setup_swap_info(si, si->prio, si->zeromap); > _enable_swap_info(si); > spin_unlock(&si->lock); > spin_unlock(&swap_lock); > @@ -2735,8 +2736,8 @@ static void wait_for_allocation(struct swap_info_st= ruct *si) > } > } > > -static void free_cluster_info(struct swap_cluster_info *cluster_info, > - unsigned long maxpages) > +static void free_swap_cluster_info(struct swap_cluster_info *cluster_inf= o, > + unsigned long maxpages) > { > struct swap_cluster_info *ci; > int i, nr_clusters =3D DIV_ROUND_UP(maxpages, SWAPFILE_CLUSTER); > @@ -2894,7 +2895,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, speci= alfile) > p->global_cluster =3D NULL; > vfree(swap_map); > kvfree(zeromap); > - free_cluster_info(cluster_info, maxpages); > + free_swap_cluster_info(cluster_info, maxpages); > /* Destroy swap account information */ > swap_cgroup_swapoff(p->type); > > @@ -3243,10 +3244,15 @@ static unsigned long read_swap_header(struct swap= _info_struct *si, > > static int setup_swap_map(struct swap_info_struct *si, > union swap_header *swap_header, > - unsigned char *swap_map, > unsigned long maxpages) > { > unsigned long i; > + unsigned char *swap_map; > + > + swap_map =3D vzalloc(maxpages); > + si->swap_map =3D swap_map; > + if (!swap_map) > + return -ENOMEM; > > swap_map[0] =3D SWAP_MAP_BAD; /* omit header page */ > for (i =3D 0; i < swap_header->info.nr_badpages; i++) { > @@ -3267,9 +3273,9 @@ static int setup_swap_map(struct swap_info_struct *= si, > return 0; > } > > -static struct swap_cluster_info *setup_clusters(struct swap_info_struct = *si, > - union swap_header *swap_h= eader, > - unsigned long maxpages) > +static int setup_swap_clusters_info(struct swap_info_struct *si, > + union swap_header *swap_header, > + unsigned long maxpages) > { > unsigned long nr_clusters =3D DIV_ROUND_UP(maxpages, SWAPFILE_CLU= STER); > struct swap_cluster_info *cluster_info; > @@ -3339,10 +3345,11 @@ static struct swap_cluster_info *setup_clusters(s= truct swap_info_struct *si, > } > } > > - return cluster_info; > + si->cluster_info =3D cluster_info; > + return 0; > err: > - free_cluster_info(cluster_info, maxpages); > - return ERR_PTR(err); > + free_swap_cluster_info(cluster_info, maxpages); > + return err; > } > > SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flag= s) > @@ -3358,9 +3365,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specia= lfile, int, swap_flags) > int nr_extents; > sector_t span; > unsigned long maxpages; > - unsigned char *swap_map =3D NULL; > unsigned long *zeromap =3D NULL; > - struct swap_cluster_info *cluster_info =3D NULL; > struct folio *folio =3D NULL; > struct inode *inode =3D NULL; > bool inced_nr_rotate_swap =3D false; > @@ -3371,6 +3376,11 @@ SYSCALL_DEFINE2(swapon, const char __user *, speci= alfile, int, swap_flags) > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > > + /* > + * Allocate or reuse existing !SWP_USED swap_info. The returned > + * si will stay in a dying status, so nothing will access its con= tent > + * until enable_swap_info resurrects its percpu ref and expose it= . > + */ > si =3D alloc_swap_info(); > if (IS_ERR(si)) > return PTR_ERR(si); > @@ -3453,18 +3463,17 @@ SYSCALL_DEFINE2(swapon, const char __user *, spec= ialfile, int, swap_flags) > > maxpages =3D si->max; > > - /* OK, set up the swap map and apply the bad block list */ > - swap_map =3D vzalloc(maxpages); > - if (!swap_map) { > - error =3D -ENOMEM; > + /* Setup the swap map and apply bad block */ > + error =3D setup_swap_map(si, swap_header, maxpages); > + if (error) > goto bad_swap_unlock_inode; > - } > > - error =3D swap_cgroup_swapon(si->type, maxpages); > + /* Set up the swap cluster info */ > + error =3D setup_swap_clusters_info(si, swap_header, maxpages); > if (error) > goto bad_swap_unlock_inode; > > - error =3D setup_swap_map(si, swap_header, swap_map, maxpages); > + error =3D swap_cgroup_swapon(si->type, maxpages); > if (error) > goto bad_swap_unlock_inode; > > @@ -3492,13 +3501,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, speci= alfile, int, swap_flags) > inced_nr_rotate_swap =3D true; > } > > - cluster_info =3D setup_clusters(si, swap_header, maxpages); > - if (IS_ERR(cluster_info)) { > - error =3D PTR_ERR(cluster_info); > - cluster_info =3D NULL; > - goto bad_swap_unlock_inode; > - } > - > if ((swap_flags & SWAP_FLAG_DISCARD) && > si->bdev && bdev_max_discard_sectors(si->bdev)) { > /* > @@ -3551,7 +3553,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specia= lfile, int, swap_flags) > prio =3D swap_flags & SWAP_FLAG_PRIO_MASK; > > si->swap_file =3D swap_file; > - enable_swap_info(si, prio, swap_map, cluster_info, zeromap); > + > + /* Sets SWP_WRITEOK, resurrect the percpu ref, expose the swap de= vice */ > + enable_swap_info(si, prio, zeromap); > > pr_info("Adding %uk swap on %s. Priority:%d extents:%d across:%l= luk %s%s%s%s\n", > K(si->pages), name->name, si->prio, nr_extents, > @@ -3577,13 +3581,18 @@ SYSCALL_DEFINE2(swapon, const char __user *, spec= ialfile, int, swap_flags) > inode =3D NULL; > destroy_swap_extents(si, swap_file); > swap_cgroup_swapoff(si->type); > + vfree(si->swap_map); > + si->swap_map =3D NULL; > + free_swap_cluster_info(si->cluster_info, si->max); > + si->cluster_info =3D NULL; > + /* > + * Clear the SWP_USED flag after all resources are freed so > + * alloc_swap_info can reuse this si safely. > + */ > spin_lock(&swap_lock); > si->flags =3D 0; > spin_unlock(&swap_lock); > - vfree(swap_map); > kvfree(zeromap); > - if (cluster_info) > - free_cluster_info(cluster_info, maxpages); > if (inced_nr_rotate_swap) > atomic_dec(&nr_rotate_swap); > if (swap_file) > > -- > 2.52.0 > >