@@ -371,6 +371,7 @@ static void __address_space_init_once(struct address_space *mapping)
INIT_LIST_HEAD(&mapping->private_list);
spin_lock_init(&mapping->private_lock);
mapping->i_mmap = RB_ROOT_CACHED;
+ atomic64_set(&mapping->mmap_count, 0);
}
void address_space_init_once(struct address_space *mapping)
@@ -1214,6 +1214,14 @@ xfs_ioctl_setattr_dax_invalidate(
goto out_unlock;
}
+ /*
+ * If there is a mapping in place we must remain in our current state.
+ */
+ if (inode_has_mappings(inode)) {
+ error = -EBUSY;
+ goto out_unlock;
+ }
+
error = filemap_write_and_wait(inode->i_mapping);
if (error)
goto out_unlock;
@@ -459,6 +459,7 @@ struct address_space {
#endif
struct rb_root_cached i_mmap;
struct rw_semaphore i_mmap_rwsem;
+ atomic64_t mmap_count;
unsigned long nrpages;
unsigned long nrexceptional;
pgoff_t writeback_index;
@@ -1951,6 +1952,11 @@ static inline void enable_dax_state_static_branch(void)
#define enable_dax_state_static_branch()
#endif /* CONFIG_FS_DAX */
+static inline bool inode_has_mappings(struct inode *inode)
+{
+ return (atomic64_read(&inode->i_mapping->mmap_count) != 0);
+}
+
static inline ssize_t call_read_iter(struct file *file, struct kiocb *kio,
struct iov_iter *iter)
{
@@ -171,12 +171,17 @@ void unlink_file_vma(struct vm_area_struct *vma)
static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
{
struct vm_area_struct *next = vma->vm_next;
+ struct file *f = vma->vm_file;
might_sleep();
if (vma->vm_ops && vma->vm_ops->close)
vma->vm_ops->close(vma);
- if (vma->vm_file)
- fput(vma->vm_file);
+ if (f) {
+ struct inode *inode = file_inode(f);
+ if (inode)
+ atomic64_dec(&inode->i_mapping->mmap_count);
+ fput(f);
+ }
mpol_put(vma_policy(vma));
vm_area_free(vma);
return next;
@@ -1830,6 +1835,16 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
vma_set_page_prot(vma);
+ /*
+ * Track if there is mapping in place such that a state change
+ * does not occur on a file which is mapped
+ */
+ if (file) {
+ struct inode *inode = file_inode(file);
+
+ atomic64_inc(&inode->i_mapping->mmap_count);
+ }
+
return addr;
unmap_and_free_vma: