@@ -372,6 +372,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)
@@ -1207,6 +1207,15 @@ xfs_ioctl_setattr_dax_invalidate(
/* lock, flush and invalidate mapping in preparation for flag change */
xfs_ilock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);
+
+ /*
+ * 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;
@@ -438,6 +438,7 @@ int pagecache_write_end(struct file *, struct address_space *mapping,
* @nr_thps: Number of THPs in the pagecache (non-shmem only).
* @i_mmap: Tree of private and shared mappings.
* @i_mmap_rwsem: Protects @i_mmap and @i_mmap_writable.
+ * @mmap_count: The number of times this AS has been mmap'ed
* @nrpages: Number of page entries, protected by the i_pages lock.
* @nrexceptional: Shadow or DAX entries, protected by the i_pages lock.
* @writeback_index: Writeback starts here.
@@ -459,6 +460,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;
@@ -1937,6 +1939,11 @@ static inline void inode_aops_up_write(struct inode *inode)
#define inode_aops_up_write(inode) do { (void)(inode); } while (0)
#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: