aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_iops.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 72129493e9d3..ec6dcdc181ee 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -849,6 +849,36 @@ xfs_setattr_size(
849 return error; 849 return error;
850 truncate_setsize(inode, newsize); 850 truncate_setsize(inode, newsize);
851 851
852 /*
853 * The "we can't serialise against page faults" pain gets worse.
854 *
855 * If the file is mapped then we have to clean the page at the old EOF
856 * when extending the file. Extending the file can expose changes the
857 * underlying page mapping (e.g. from beyond EOF to a hole or
858 * unwritten), and so on the next attempt to write to that page we need
859 * to remap it for write. i.e. we need .page_mkwrite() to be called.
860 * Hence we need to clean the page to clean the pte and so a new write
861 * fault will be triggered appropriately.
862 *
863 * If we do it before we change the inode size, then we can race with a
864 * page fault that maps the page with exactly the same problem. If we do
865 * it after we change the file size, then a new page fault can come in
866 * and allocate space before we've run the rest of the truncate
867 * transaction. That's kinda grotesque, but it's better than have data
868 * over a hole, and so that's the lesser evil that has been chosen here.
869 *
870 * The real solution, however, is to have some mechanism for locking out
871 * page faults while a truncate is in progress.
872 */
873 if (newsize > oldsize && mapping_mapped(VFS_I(ip)->i_mapping)) {
874 error = filemap_write_and_wait_range(
875 VFS_I(ip)->i_mapping,
876 round_down(oldsize, PAGE_CACHE_SIZE),
877 round_up(oldsize, PAGE_CACHE_SIZE) - 1);
878 if (error)
879 return error;
880 }
881
852 tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); 882 tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
853 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0); 883 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
854 if (error) 884 if (error)