fix #1633: potential deadlock with shmem
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
This commit is contained in:
		
							parent
							
								
									498bdfe5e5
								
							
						
					
					
						commit
						b25749a58c
					
				| @ -0,0 +1,103 @@ | |||||||
|  | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> | ||||||
|  | Date: Fri, 23 Mar 2018 09:19:21 +0100 | ||||||
|  | Subject: [PATCH] mm/shmem: do not wait for lock_page() in | ||||||
|  |  shmem_unused_huge_shrink() | ||||||
|  | MIME-Version: 1.0 | ||||||
|  | Content-Type: text/plain; charset=UTF-8 | ||||||
|  | Content-Transfer-Encoding: 8bit | ||||||
|  | 
 | ||||||
|  | shmem_unused_huge_shrink() gets called from reclaim path.  Waiting for | ||||||
|  | page lock may lead to deadlock there. | ||||||
|  | 
 | ||||||
|  | There was a bug report that may be attributed to this: | ||||||
|  | 
 | ||||||
|  | http://lkml.kernel.org/r/alpine.LRH.2.11.1801242349220.30642@mail.ewheeler.net | ||||||
|  | 
 | ||||||
|  | Replace lock_page() with trylock_page() and skip the page if we failed to | ||||||
|  | lock it.  We will get to the page on the next scan. | ||||||
|  | 
 | ||||||
|  | We can test for the PageTransHuge() outside the page lock as we only need | ||||||
|  | protection against splitting the page under us.  Holding pin oni the page | ||||||
|  | is enough for this. | ||||||
|  | 
 | ||||||
|  | Link: http://lkml.kernel.org/r/20180316210830.43738-1-kirill.shutemov@linux.intel.com | ||||||
|  | Fixes: 779750d20b93 ("shmem: split huge pages beyond i_size under memory pressure") | ||||||
|  | Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> | ||||||
|  | Reported-by: Eric Wheeler <linux-mm@lists.ewheeler.net> | ||||||
|  | Acked-by: Michal Hocko <mhocko@suse.com> | ||||||
|  | Reviewed-by: Andrew Morton <akpm@linux-foundation.org> | ||||||
|  | Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | ||||||
|  | Cc: Hugh Dickins <hughd@google.com> | ||||||
|  | Cc: <stable@vger.kernel.org>	[4.8+] | ||||||
|  | Signed-off-by: Andrew Morton <> | ||||||
|  | (cherry-picked from https://git.kernel.org/pub/scm/linux/kernel/git/mhocko/mm.git/commit/?h=since-4.15&id=73eccc61c701ee7b4223aea2079542a712feeea7) | ||||||
|  | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | ||||||
|  | ---
 | ||||||
|  |  mm/shmem.c | 31 ++++++++++++++++++++----------- | ||||||
|  |  1 file changed, 20 insertions(+), 11 deletions(-) | ||||||
|  | 
 | ||||||
|  | diff --git a/mm/shmem.c b/mm/shmem.c
 | ||||||
|  | index f6695c111086..800482fe6ed6 100644
 | ||||||
|  | --- a/mm/shmem.c
 | ||||||
|  | +++ b/mm/shmem.c
 | ||||||
|  | @@ -497,36 +497,45 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
 | ||||||
|  |  		info = list_entry(pos, struct shmem_inode_info, shrinklist); | ||||||
|  |  		inode = &info->vfs_inode; | ||||||
|  |   | ||||||
|  | -		if (nr_to_split && split >= nr_to_split) {
 | ||||||
|  | -			iput(inode);
 | ||||||
|  | -			continue;
 | ||||||
|  | -		}
 | ||||||
|  | +		if (nr_to_split && split >= nr_to_split)
 | ||||||
|  | +			goto leave;
 | ||||||
|  |   | ||||||
|  | -		page = find_lock_page(inode->i_mapping,
 | ||||||
|  | +		page = find_get_page(inode->i_mapping,
 | ||||||
|  |  				(inode->i_size & HPAGE_PMD_MASK) >> PAGE_SHIFT); | ||||||
|  |  		if (!page) | ||||||
|  |  			goto drop; | ||||||
|  |   | ||||||
|  | +		/* No huge page at the end of the file: nothing to split */
 | ||||||
|  |  		if (!PageTransHuge(page)) { | ||||||
|  | -			unlock_page(page);
 | ||||||
|  |  			put_page(page); | ||||||
|  |  			goto drop; | ||||||
|  |  		} | ||||||
|  |   | ||||||
|  | +		/*
 | ||||||
|  | +		 * Leave the inode on the list if we failed to lock
 | ||||||
|  | +		 * the page at this time.
 | ||||||
|  | +		 *
 | ||||||
|  | +		 * Waiting for the lock may lead to deadlock in the
 | ||||||
|  | +		 * reclaim path.
 | ||||||
|  | +		 */
 | ||||||
|  | +		if (!trylock_page(page)) {
 | ||||||
|  | +			put_page(page);
 | ||||||
|  | +			goto leave;
 | ||||||
|  | +		}
 | ||||||
|  | +
 | ||||||
|  |  		ret = split_huge_page(page); | ||||||
|  |  		unlock_page(page); | ||||||
|  |  		put_page(page); | ||||||
|  |   | ||||||
|  | -		if (ret) {
 | ||||||
|  | -			/* split failed: leave it on the list */
 | ||||||
|  | -			iput(inode);
 | ||||||
|  | -			continue;
 | ||||||
|  | -		}
 | ||||||
|  | +		/* If split failed leave the inode on the list */
 | ||||||
|  | +		if (ret)
 | ||||||
|  | +			goto leave;
 | ||||||
|  |   | ||||||
|  |  		split++; | ||||||
|  |  drop: | ||||||
|  |  		list_del_init(&info->shrinklist); | ||||||
|  |  		removed++; | ||||||
|  | +leave:
 | ||||||
|  |  		iput(inode); | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -- 
 | ||||||
|  | 2.14.2 | ||||||
|  | 
 | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Fabian Grünbichler
						Fabian Grünbichler