diff --git a/fs/xfs/xfs_pnfs.c b/fs/xfs/xfs_pnfs.c index f8535ecde21a..ab385617003a 100644 --- a/fs/xfs/xfs_pnfs.c +++ b/fs/xfs/xfs_pnfs.c @@ -183,13 +183,28 @@ xfs_fs_map_blocks( offset_fsb = XFS_B_TO_FSBT(mp, offset); lock_flags = xfs_ilock_data_map_shared(ip); - /* request mappings for the specified range only */ + /* + * Map to the end of the extent that covers the start of the range, + * so that a client doing I/O in pieces gets a layout it can use for + * the pieces that follow. Never map anything before the start of + * the range: nfsd calls in here once per extent of a LAYOUTGET, for + * the range that is left after the previous extent, and the mapping + * can change in between, so a mapping that reaches back can overlap + * one already in the layout. Don't extend the mapping past EOF + * beyond the range either: xfs_free_eofblocks() can free blocks past + * EOF without breaking the layout. + */ error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, - &imap, &nimaps, 0); + &imap, &nimaps, XFS_BMAPI_ENTIRE); if (error) { xfs_iunlock(ip, lock_flags); goto out_unlock; } + if (nimaps) + xfs_trim_extent(&imap, offset_fsb, + max_t(xfs_fileoff_t, end_fsb, + XFS_B_TO_FSB(mp, XFS_ISIZE(ip))) - + offset_fsb); seq = xfs_iomap_inode_sequence(ip, 0); ASSERT(!nimaps || imap.br_startblock != DELAYSTARTBLOCK);