diff options
Diffstat (limited to 'mm/truncate.c')
| -rw-r--r-- | mm/truncate.c | 75 | 
1 files changed, 61 insertions, 14 deletions
diff --git a/mm/truncate.c b/mm/truncate.c index fd97f1dbce29..dd7b24e083c5 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -24,20 +24,12 @@  #include <linux/rmap.h>  #include "internal.h" -static void clear_exceptional_entry(struct address_space *mapping, -				    pgoff_t index, void *entry) +static void clear_shadow_entry(struct address_space *mapping, pgoff_t index, +			       void *entry)  {  	struct radix_tree_node *node;  	void **slot; -	/* Handled by shmem itself */ -	if (shmem_mapping(mapping)) -		return; - -	if (dax_mapping(mapping)) { -		dax_delete_mapping_entry(mapping, index); -		return; -	}  	spin_lock_irq(&mapping->tree_lock);  	/*  	 * Regular page slots are stabilized by the page lock even @@ -55,6 +47,56 @@ unlock:  	spin_unlock_irq(&mapping->tree_lock);  } +/* + * Unconditionally remove exceptional entry. Usually called from truncate path. + */ +static void truncate_exceptional_entry(struct address_space *mapping, +				       pgoff_t index, void *entry) +{ +	/* Handled by shmem itself */ +	if (shmem_mapping(mapping)) +		return; + +	if (dax_mapping(mapping)) { +		dax_delete_mapping_entry(mapping, index); +		return; +	} +	clear_shadow_entry(mapping, index, entry); +} + +/* + * Invalidate exceptional entry if easily possible. This handles exceptional + * entries for invalidate_inode_pages() so for DAX it evicts only unlocked and + * clean entries. + */ +static int invalidate_exceptional_entry(struct address_space *mapping, +					pgoff_t index, void *entry) +{ +	/* Handled by shmem itself */ +	if (shmem_mapping(mapping)) +		return 1; +	if (dax_mapping(mapping)) +		return dax_invalidate_mapping_entry(mapping, index); +	clear_shadow_entry(mapping, index, entry); +	return 1; +} + +/* + * Invalidate exceptional entry if clean. This handles exceptional entries for + * invalidate_inode_pages2() so for DAX it evicts only clean entries. + */ +static int invalidate_exceptional_entry2(struct address_space *mapping, +					 pgoff_t index, void *entry) +{ +	/* Handled by shmem itself */ +	if (shmem_mapping(mapping)) +		return 1; +	if (dax_mapping(mapping)) +		return dax_invalidate_mapping_entry_sync(mapping, index); +	clear_shadow_entry(mapping, index, entry); +	return 1; +} +  /**   * do_invalidatepage - invalidate part or all of a page   * @page: the page which is affected @@ -262,7 +304,8 @@ void truncate_inode_pages_range(struct address_space *mapping,  				break;  			if (radix_tree_exceptional_entry(page)) { -				clear_exceptional_entry(mapping, index, page); +				truncate_exceptional_entry(mapping, index, +							   page);  				continue;  			} @@ -351,7 +394,8 @@ void truncate_inode_pages_range(struct address_space *mapping,  			}  			if (radix_tree_exceptional_entry(page)) { -				clear_exceptional_entry(mapping, index, page); +				truncate_exceptional_entry(mapping, index, +							   page);  				continue;  			} @@ -470,7 +514,8 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,  				break;  			if (radix_tree_exceptional_entry(page)) { -				clear_exceptional_entry(mapping, index, page); +				invalidate_exceptional_entry(mapping, index, +							     page);  				continue;  			} @@ -592,7 +637,9 @@ int invalidate_inode_pages2_range(struct address_space *mapping,  				break;  			if (radix_tree_exceptional_entry(page)) { -				clear_exceptional_entry(mapping, index, page); +				if (!invalidate_exceptional_entry2(mapping, +								   index, page)) +					ret = -EBUSY;  				continue;  			}  | 
