The sepcial case in shmem_recalc_inode() is tailored for shmem_writepage(). By raising swapped before nrpages is lowered directly within shmem_writepage(), we can simplify code of shmem_recalc_inode() and eliminate the need of executing the special case code for all callers of shmem_recalc_inode(). Signed-off-by: Kemeng Shi <shikemeng@xxxxxxxxxxxxxxx> --- mm/shmem.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/mm/shmem.c b/mm/shmem.c index 2349673b239b..9f5e1eccaacb 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -443,15 +443,6 @@ static void shmem_recalc_inode(struct inode *inode, long alloced, long swapped) info->swapped += swapped; freed = info->alloced - info->swapped - READ_ONCE(inode->i_mapping->nrpages); - /* - * Special case: whereas normally shmem_recalc_inode() is called - * after i_mapping->nrpages has already been adjusted (up or down), - * shmem_writepage() has to raise swapped before nrpages is lowered - - * to stop a racing shmem_recalc_inode() from thinking that a page has - * been freed. Compensate here, to avoid the need for a followup call. - */ - if (swapped > 0) - freed += swapped; if (freed > 0) info->alloced -= freed; spin_unlock(&info->lock); @@ -1694,9 +1685,16 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) list_add(&info->swaplist, &shmem_swaplist); if (!folio_alloc_swap(folio, __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN)) { - shmem_recalc_inode(inode, 0, nr_pages); + /* + * Raise swapped before nrpages is lowered to stop racing + * shmem_recalc_inode() from thinking that a page has been freed. + */ + spin_lock(&info->lock); + info->swapped += nr_pages; + spin_unlock(&info->lock); swap_shmem_alloc(folio->swap, nr_pages); shmem_delete_from_page_cache(folio, swp_to_radix_entry(folio->swap)); + shmem_recalc_inode(inode, 0, 0); mutex_unlock(&shmem_swaplist_mutex); BUG_ON(folio_mapped(folio)); -- 2.30.0