Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[firefly-linux-kernel-4.4.55.git] / mm / truncate.c
index 5b4c3a4847e93cf445081ff50085bd540cec4971..e13f22efaad741bfb0268ba577c3d34807769201 100644 (file)
@@ -304,6 +304,11 @@ EXPORT_SYMBOL(truncate_inode_pages_range);
  * @lstart: offset from which to truncate
  *
  * Called under (and serialised by) inode->i_mutex.
+ *
+ * Note: When this function returns, there can be a page in the process of
+ * deletion (inside __delete_from_page_cache()) in the specified range.  Thus
+ * mapping->nrpages can be non-zero when this function returns even after
+ * truncation of the whole mapping.
  */
 void truncate_inode_pages(struct address_space *mapping, loff_t lstart)
 {
@@ -619,9 +624,9 @@ int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end)
        mutex_lock(&inode->i_mutex);
        down_write(&inode->i_alloc_sem);
        unmap_mapping_range(mapping, offset, (end - offset), 1);
-       truncate_inode_pages_range(mapping, offset, end);
-       unmap_mapping_range(mapping, offset, (end - offset), 1);
        inode->i_op->truncate_range(inode, offset, end);
+       /* unmap again to remove racily COWed private pages */
+       unmap_mapping_range(mapping, offset, (end - offset), 1);
        up_write(&inode->i_alloc_sem);
        mutex_unlock(&inode->i_mutex);