diff options
Diffstat (limited to 'fs/xfs/xfs_aops.c')
-rw-r--r-- | fs/xfs/xfs_aops.c | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 4fc526a27a94..9c6a830da0ee 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -390,6 +390,19 @@ xfs_map_blocks( if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; + /* + * Truncate can race with writeback since writeback doesn't take the + * iolock and truncate decreases the file size before it starts + * truncating the pages between new_size and old_size. Therefore, we + * can end up in the situation where writeback gets a CoW fork mapping + * but the truncate makes the mapping invalid and we end up in here + * trying to get a new mapping. Bail out here so that we simply never + * get a valid mapping and so we drop the write altogether. The page + * truncation will kill the contents anyway. + */ + if (type == XFS_IO_COW && offset > i_size_read(inode)) + return 0; + ASSERT(type != XFS_IO_COW); if (type == XFS_IO_UNWRITTEN) bmapi_flags |= XFS_BMAPI_IGSTATE; @@ -791,7 +804,7 @@ xfs_aops_discard_page( goto out_invalidate; xfs_alert(ip->i_mount, - "page discard on page %p, inode 0x%llx, offset %llu.", + "page discard on page "PTR_FMT", inode 0x%llx, offset %llu.", page, ip->i_ino, offset); xfs_ilock(ip, XFS_ILOCK_EXCL); |