mm: swap: enforce updating inuse_pages at the end of swap_range_free()
[sfrench/cifs-2.6.git] / mm / swapfile.c
index 0c6dde8b8604d89d6e9543c393442db8ea999d34..a8edaf4e5b8ad94f4f594ba7d1dcd201072e44af 100644 (file)
@@ -737,8 +737,6 @@ static void swap_range_free(struct swap_info_struct *si, unsigned long offset,
                if (was_full && (si->flags & SWP_WRITEOK))
                        add_to_avail_list(si);
        }
-       atomic_long_add(nr_entries, &nr_swap_pages);
-       WRITE_ONCE(si->inuse_pages, si->inuse_pages - nr_entries);
        if (si->flags & SWP_BLKDEV)
                swap_slot_free_notify =
                        si->bdev->bd_disk->fops->swap_slot_free_notify;
@@ -752,6 +750,14 @@ static void swap_range_free(struct swap_info_struct *si, unsigned long offset,
                offset++;
        }
        clear_shadow_from_swap_cache(si->type, begin, end);
+
+       /*
+        * Make sure that try_to_unuse() observes si->inuse_pages reaching 0
+        * only after the above cleanups are done.
+        */
+       smp_wmb();
+       atomic_long_add(nr_entries, &nr_swap_pages);
+       WRITE_ONCE(si->inuse_pages, si->inuse_pages - nr_entries);
 }
 
 static void set_cluster_next(struct swap_info_struct *si, unsigned long next)
@@ -2049,7 +2055,7 @@ static int try_to_unuse(unsigned int type)
        unsigned int i;
 
        if (!READ_ONCE(si->inuse_pages))
-               return 0;
+               goto success;
 
 retry:
        retval = shmem_unuse(type);
@@ -2130,6 +2136,12 @@ retry:
                return -EINTR;
        }
 
+success:
+       /*
+        * Make sure that further cleanups after try_to_unuse() returns happen
+        * after swap_range_free() reduces si->inuse_pages to 0.
+        */
+       smp_mb();
        return 0;
 }