Commit c8945306 authored by Miaohe Lin's avatar Miaohe Lin Committed by akpm

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.comSigned-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
...@@ -695,7 +695,7 @@ static void swap_range_alloc(struct swap_info_struct *si, unsigned long offset, ...@@ -695,7 +695,7 @@ static void swap_range_alloc(struct swap_info_struct *si, unsigned long offset,
si->lowest_bit += nr_entries; si->lowest_bit += nr_entries;
if (end == si->highest_bit) if (end == si->highest_bit)
WRITE_ONCE(si->highest_bit, si->highest_bit - nr_entries); 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) { if (si->inuse_pages == si->pages) {
si->lowest_bit = si->max; si->lowest_bit = si->max;
si->highest_bit = 0; si->highest_bit = 0;
...@@ -732,7 +732,7 @@ static void swap_range_free(struct swap_info_struct *si, unsigned long offset, ...@@ -732,7 +732,7 @@ static void swap_range_free(struct swap_info_struct *si, unsigned long offset,
add_to_avail_list(si); add_to_avail_list(si);
} }
atomic_long_add(nr_entries, &nr_swap_pages); 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) if (si->flags & SWP_BLKDEV)
swap_slot_free_notify = swap_slot_free_notify =
si->bdev->bd_disk->fops->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) ...@@ -2640,7 +2640,7 @@ static int swap_show(struct seq_file *swap, void *v)
} }
bytes = si->pages << (PAGE_SHIFT - 10); 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; file = si->swap_file;
len = seq_file_path(swap, file, " \t\n\\"); len = seq_file_path(swap, file, " \t\n\\");
...@@ -3259,7 +3259,7 @@ void si_swapinfo(struct sysinfo *val) ...@@ -3259,7 +3259,7 @@ void si_swapinfo(struct sysinfo *val)
struct swap_info_struct *si = swap_info[type]; struct swap_info_struct *si = swap_info[type];
if ((si->flags & SWP_USED) && !(si->flags & SWP_WRITEOK)) 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->freeswap = atomic_long_read(&nr_swap_pages) + nr_to_be_unused;
val->totalswap = total_swap_pages + nr_to_be_unused; val->totalswap = total_swap_pages + nr_to_be_unused;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment