diff options
Diffstat (limited to 'mm/shmem.c')
| -rw-r--r-- | mm/shmem.c | 31 | 
1 files changed, 20 insertions, 11 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 1907688b75ee..b85919243399 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -493,36 +493,45 @@ next:  		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);  	}  | 

