Commit c8945306 authored by Miaohe Lin's avatar Miaohe Lin Committed by Andrew Morton
Browse files

mm/swapfile: fix possible data races of inuse_pages

si->inuse_pages could still be accessed concurrently now.  The plain reads
outside si->lock critical section, i.e.  swap_show and si_swapinfo, which
results in data races.  READ_ONCE and WRITE_ONCE is used to fix such data
races.  Note these data races should be ok because they're just used for
showing swap info.

[linmiaohe@huawei.com: use WRITE_ONCE to pair with READ_ONCE]
  Link: https://lkml.kernel.org/r/20220625093346.48894-2-linmiaohe@huawei.com
Link: https://lkml.kernel.org/r/20220608144031.829-3-linmiaohe@huawei.com


Signed-off-by: default avatarMiaohe Lin <linmiaohe@huawei.com>
Reviewed-by: default avatarDavid Hildenbrand <david@redhat.com>
Reviewed-by: default avatar"Huang, Ying" <ying.huang@intel.com>
Cc: Hugh Dickins <hughd@google.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 5e21f2d5
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -695,7 +695,7 @@ static void swap_range_alloc(struct swap_info_struct *si, unsigned long offset,
		si->lowest_bit += nr_entries;
	if (end == si->highest_bit)
		WRITE_ONCE(si->highest_bit, si->highest_bit - nr_entries);
	si->inuse_pages += nr_entries;
	WRITE_ONCE(si->inuse_pages, si->inuse_pages + nr_entries);
	if (si->inuse_pages == si->pages) {
		si->lowest_bit = si->max;
		si->highest_bit = 0;
@@ -732,7 +732,7 @@ static void swap_range_free(struct swap_info_struct *si, unsigned long offset,
			add_to_avail_list(si);
	}
	atomic_long_add(nr_entries, &nr_swap_pages);
	si->inuse_pages -= nr_entries;
	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;
@@ -2640,7 +2640,7 @@ static int swap_show(struct seq_file *swap, void *v)
	}

	bytes = si->pages << (PAGE_SHIFT - 10);
	inuse = si->inuse_pages << (PAGE_SHIFT - 10);
	inuse = READ_ONCE(si->inuse_pages) << (PAGE_SHIFT - 10);

	file = si->swap_file;
	len = seq_file_path(swap, file, " \t\n\\");
@@ -3259,7 +3259,7 @@ void si_swapinfo(struct sysinfo *val)
		struct swap_info_struct *si = swap_info[type];

		if ((si->flags & SWP_USED) && !(si->flags & SWP_WRITEOK))
			nr_to_be_unused += si->inuse_pages;
			nr_to_be_unused += READ_ONCE(si->inuse_pages);
	}
	val->freeswap = atomic_long_read(&nr_swap_pages) + nr_to_be_unused;
	val->totalswap = total_swap_pages + nr_to_be_unused;