From: Daejun Park Move the part of xfs_fs_map_blocks() that maps one extent, and allocates it first if it is a hole in a write layout, into a new helper, xfs_fs_map_extent(), so that the next patch can call it for each extent of a layout. The inode update and the log force after an allocation stay in xfs_fs_map_blocks(). No change in behavior. Signed-off-by: Daejun Park --- fs/xfs/xfs_pnfs.c | 119 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 47 deletions(-) diff --git a/fs/xfs/xfs_pnfs.c b/fs/xfs/xfs_pnfs.c index 055e6fb299..81e1ae0351 100644 --- a/fs/xfs/xfs_pnfs.c +++ b/fs/xfs/xfs_pnfs.c @@ -113,6 +113,73 @@ xfs_fs_map_update_inode( return xfs_trans_commit(tp); } +/* + * Map the extent of a pNFS layout that starts at @offset_fsb, allocating it + * first if it is a hole in a write layout. The mapping may end before or + * after @end. Called with the iolock held. + */ +static int +xfs_fs_map_extent( + struct xfs_inode *ip, + xfs_fileoff_t offset_fsb, + loff_t end, + bool write, + struct xfs_bmbt_irec *imap, + u64 *seq, + bool *allocated) +{ + struct xfs_mount *mp = ip->i_mount; + xfs_fileoff_t end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)end); + int nimaps = 1; + uint lock_flags; + int error; + + lock_flags = xfs_ilock_data_map_shared(ip); + /* + * 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, XFS_BMAPI_ENTIRE); + if (error) { + xfs_iunlock(ip, lock_flags); + return error; + } + 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); + + if (!write || (nimaps && imap->br_startblock != HOLESTARTBLOCK)) { + xfs_iunlock(ip, lock_flags); + return 0; + } + + if (end > XFS_ISIZE(ip)) + end_fsb = xfs_iomap_eof_align_last_fsb(ip, end_fsb); + else if (nimaps) + end_fsb = min(end_fsb, imap->br_startoff + imap->br_blockcount); + xfs_iunlock(ip, lock_flags); + + error = xfs_iomap_write_direct(ip, offset_fsb, end_fsb - offset_fsb, 0, + imap, seq); + if (error) + return error; + *allocated = true; + return 0; +} + /* * Get a layout for the pNFS client. */ @@ -129,10 +196,8 @@ xfs_fs_map_blocks( struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; struct xfs_bmbt_irec imap; - xfs_fileoff_t offset_fsb, end_fsb; + bool allocated = false; loff_t limit; - int nimaps = 1; - uint lock_flags; int error = 0; u64 seq; @@ -180,49 +245,12 @@ xfs_fs_map_blocks( if (WARN_ON_ONCE(error)) goto out_unlock; - end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + length); - offset_fsb = XFS_B_TO_FSBT(mp, offset); - - lock_flags = xfs_ilock_data_map_shared(ip); - /* - * 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, XFS_BMAPI_ENTIRE); - if (error) { - xfs_iunlock(ip, lock_flags); + error = xfs_fs_map_extent(ip, XFS_B_TO_FSBT(mp, offset), + offset + length, write, &imap, &seq, &allocated); + if (error) 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); - - if (write && (!nimaps || imap.br_startblock == HOLESTARTBLOCK)) { - if (offset + length > XFS_ISIZE(ip)) - end_fsb = xfs_iomap_eof_align_last_fsb(ip, end_fsb); - else if (nimaps && imap.br_startblock == HOLESTARTBLOCK) - end_fsb = min(end_fsb, imap.br_startoff + - imap.br_blockcount); - xfs_iunlock(ip, lock_flags); - - error = xfs_iomap_write_direct(ip, offset_fsb, - end_fsb - offset_fsb, 0, &imap, &seq); - if (error) - goto out_unlock; + if (allocated) { /* * Ensure the next transaction is committed synchronously so * that the blocks allocated and handed out to the client are @@ -233,9 +261,6 @@ xfs_fs_map_blocks( error = xfs_log_force_inode(ip); if (error) goto out_unlock; - - } else { - xfs_iunlock(ip, lock_flags); } xfs_iunlock(ip, XFS_IOLOCK_EXCL); -- 2.43.0