]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mm/swap: remove redundant swap device reference in alloc/free
authorYoungjun Park <youngjun.park@lge.com>
Mon, 23 Mar 2026 16:08:22 +0000 (01:08 +0900)
committerAndrew Morton <akpm@linux-foundation.org>
Tue, 9 Jun 2026 01:21:32 +0000 (18:21 -0700)
In the previous commit, uswsusp was modified to pin the swap device when
the swap type is determined, ensuring the device remains valid throughout
the hibernation I/O path.

Therefore, it is no longer necessary to repeatedly get and put the swap
device reference for each swap slot allocation and free operation.

For hibernation via the sysfs interface, user-space tasks are frozen
before swap allocation begins, so swapoff cannot race with allocation.
After resume, tasks remain frozen while swap slots are freed, so
additional reference management is not required there either.

Remove the redundant swap device get/put operations from the hibernation
swap allocation and free paths.

Also remove the SWP_WRITEOK check before allocation, as the cluster
allocation logic already validates the swap device state.

Update function comments to document the caller's responsibility for
ensuring swap device stability.

Link: https://lore.kernel.org/20260323160822.1409904-3-youngjun.park@lge.com
Signed-off-by: Youngjun Park <youngjun.park@lge.com>
Reviewed-by: Kairui Song <kasong@tencent.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Chris Li <chrisl@kernel.org>
Cc: Kemeng Shi <shikemeng@huaweicloud.com>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: "Rafael J . Wysocki" <rafael@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/swapfile.c

index 5e1e605ad9a1e85c78150e91e0bbbc2c3f884312..78b49b0658adde63c92a157ffaef7deae33c834f 100644 (file)
@@ -2138,7 +2138,16 @@ out:
 }
 
 #ifdef CONFIG_HIBERNATION
-/* Allocate a slot for hibernation */
+/**
+ * swap_alloc_hibernation_slot() - Allocate a swap slot for hibernation.
+ * @type: swap device type index to allocate from.
+ *
+ * The caller must ensure the swap device is stable, either by pinning
+ * it (SWP_HIBERNATION) or by freezing user-space.
+ *
+ * Return: a valid swp_entry_t on success, or an empty entry (val == 0)
+ * on failure.
+ */
 swp_entry_t swap_alloc_hibernation_slot(int type)
 {
        struct swap_info_struct *pcp_si, *si = swap_type_to_info(type);
@@ -2149,46 +2158,42 @@ swp_entry_t swap_alloc_hibernation_slot(int type)
        if (!si)
                goto fail;
 
-       /* This is called for allocating swap entry, not cache */
-       if (get_swap_device_info(si)) {
-               if (si->flags & SWP_WRITEOK) {
-                       /*
-                        * Try the local cluster first if it matches the device. If
-                        * not, try grab a new cluster and override local cluster.
-                        */
-                       local_lock(&percpu_swap_cluster.lock);
-                       pcp_si = this_cpu_read(percpu_swap_cluster.si[0]);
-                       pcp_offset = this_cpu_read(percpu_swap_cluster.offset[0]);
-                       if (pcp_si == si && pcp_offset) {
-                               ci = swap_cluster_lock(si, pcp_offset);
-                               if (cluster_is_usable(ci, 0))
-                                       offset = alloc_swap_scan_cluster(si, ci, NULL, pcp_offset);
-                               else
-                                       swap_cluster_unlock(ci);
-                       }
-                       if (!offset)
-                               offset = cluster_alloc_swap_entry(si, NULL);
-                       local_unlock(&percpu_swap_cluster.lock);
-                       if (offset)
-                               entry = swp_entry(si->type, offset);
-               }
-               put_swap_device(si);
+       /*
+        * Try the local cluster first if it matches the device. If
+        * not, try grab a new cluster and override local cluster.
+        */
+       local_lock(&percpu_swap_cluster.lock);
+       pcp_si = this_cpu_read(percpu_swap_cluster.si[0]);
+       pcp_offset = this_cpu_read(percpu_swap_cluster.offset[0]);
+       if (pcp_si == si && pcp_offset) {
+               ci = swap_cluster_lock(si, pcp_offset);
+               if (cluster_is_usable(ci, 0))
+                       offset = alloc_swap_scan_cluster(si, ci, NULL, pcp_offset);
+               else
+                       swap_cluster_unlock(ci);
        }
+       if (!offset)
+               offset = cluster_alloc_swap_entry(si, NULL);
+       local_unlock(&percpu_swap_cluster.lock);
+       if (offset)
+               entry = swp_entry(si->type, offset);
+
 fail:
        return entry;
 }
 
-/* Free a slot allocated by swap_alloc_hibernation_slot */
+/**
+ * swap_free_hibernation_slot() - Free a swap slot allocated for hibernation.
+ * @entry: swap entry to free.
+ *
+ * The caller must ensure the swap device is stable.
+ */
 void swap_free_hibernation_slot(swp_entry_t entry)
 {
-       struct swap_info_struct *si;
+       struct swap_info_struct *si = __swap_entry_to_info(entry);
        struct swap_cluster_info *ci;
        pgoff_t offset = swp_offset(entry);
 
-       si = get_swap_device(entry);
-       if (WARN_ON(!si))
-               return;
-
        ci = swap_cluster_lock(si, offset);
        __swap_cluster_put_entry(ci, offset % SWAPFILE_CLUSTER);
        __swap_cluster_free_entries(si, ci, offset % SWAPFILE_CLUSTER, 1);
@@ -2196,7 +2201,6 @@ void swap_free_hibernation_slot(swp_entry_t entry)
 
        /* In theory readahead might add it to the swap cache by accident */
        __try_to_reclaim_swap(si, offset, TTRS_ANYWAY);
-       put_swap_device(si);
 }
 
 static int __find_hibernation_swap_type(dev_t device, sector_t offset)