summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs/xfs_bmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/libxfs/xfs_bmap.c')
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index d3faa91369bf..b4acb032cdbe 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -4053,17 +4053,7 @@ xfs_bmapi_allocate(
bma->got.br_blockcount = bma->length;
bma->got.br_state = XFS_EXT_NORM;
- /*
- * In the data fork, a wasdelay extent has been initialized, so
- * shouldn't be flagged as unwritten.
- *
- * For the cow fork, however, we convert delalloc reservations
- * (extents allocated for speculative preallocation) to
- * allocated unwritten extents, and only convert the unwritten
- * extents to real extents when we're about to write the data.
- */
- if ((!bma->wasdel || (bma->flags & XFS_BMAPI_COWFORK)) &&
- (bma->flags & XFS_BMAPI_PREALLOC))
+ if (bma->flags & XFS_BMAPI_PREALLOC)
bma->got.br_state = XFS_EXT_UNWRITTEN;
if (bma->wasdel)
@@ -4470,8 +4460,25 @@ xfs_bmapi_convert_delalloc(
bma.length = max_t(xfs_filblks_t, bma.got.br_blockcount, MAXEXTLEN);
bma.total = XFS_EXTENTADD_SPACE_RES(ip->i_mount, XFS_DATA_FORK);
bma.minleft = xfs_bmapi_minleft(tp, ip, whichfork);
+
+ /*
+ * When we're converting the delalloc reservations backing dirty pages
+ * in the page cache, we must be careful about how we create the new
+ * extents:
+ *
+ * New CoW fork extents are created unwritten, turned into real extents
+ * when we're about to write the data to disk, and mapped into the data
+ * fork after the write finishes. End of story.
+ *
+ * New data fork extents below the on-disk EOF must be created
+ * unwritten and converted to real extents after the write succeeds
+ * to avoid exposing stale disk contents if we crash.
+ */
if (whichfork == XFS_COW_FORK)
bma.flags = XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC;
+ else if (ip->i_d.di_size > 0 &&
+ bma.offset <= XFS_B_TO_FSBT(mp, ip->i_d.di_size - 1))
+ bma.flags = XFS_BMAPI_PREALLOC;
if (!xfs_iext_peek_prev_extent(ifp, &bma.icur, &bma.prev))
bma.prev.br_startoff = NULLFILEOFF;