aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_iomap.c42
1 files changed, 30 insertions, 12 deletions
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 66e1edbfb2b2..046469fcc1b8 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -955,15 +955,29 @@ static inline bool imap_needs_alloc(struct inode *inode,
955 (IS_DAX(inode) && imap->br_state == XFS_EXT_UNWRITTEN); 955 (IS_DAX(inode) && imap->br_state == XFS_EXT_UNWRITTEN);
956} 956}
957 957
958static inline bool needs_cow_for_zeroing(struct xfs_bmbt_irec *imap, int nimaps)
959{
960 return nimaps &&
961 imap->br_startblock != HOLESTARTBLOCK &&
962 imap->br_state != XFS_EXT_UNWRITTEN;
963}
964
958static inline bool need_excl_ilock(struct xfs_inode *ip, unsigned flags) 965static inline bool need_excl_ilock(struct xfs_inode *ip, unsigned flags)
959{ 966{
960 /* 967 /*
961 * COW writes will allocate delalloc space, so we need to make sure 968 * COW writes may allocate delalloc space or convert unwritten COW
962 * to take the lock exclusively here. 969 * extents, so we need to make sure to take the lock exclusively here.
963 */ 970 */
964 if (xfs_is_reflink_inode(ip) && (flags & (IOMAP_WRITE | IOMAP_ZERO))) 971 if (xfs_is_reflink_inode(ip) && (flags & (IOMAP_WRITE | IOMAP_ZERO)))
965 return true; 972 return true;
966 if ((flags & IOMAP_DIRECT) && (flags & IOMAP_WRITE)) 973
974 /*
975 * Extents not yet cached requires exclusive access, don't block.
976 * This is an opencoded xfs_ilock_data_map_shared() to cater for the
977 * non-blocking behaviour.
978 */
979 if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE &&
980 !(ip->i_df.if_flags & XFS_IFEXTENTS))
967 return true; 981 return true;
968 return false; 982 return false;
969} 983}
@@ -993,16 +1007,18 @@ xfs_file_iomap_begin(
993 return xfs_file_iomap_begin_delay(inode, offset, length, iomap); 1007 return xfs_file_iomap_begin_delay(inode, offset, length, iomap);
994 } 1008 }
995 1009
996 if (need_excl_ilock(ip, flags)) { 1010 if (need_excl_ilock(ip, flags))
997 lockmode = XFS_ILOCK_EXCL; 1011 lockmode = XFS_ILOCK_EXCL;
998 xfs_ilock(ip, XFS_ILOCK_EXCL); 1012 else
999 } else { 1013 lockmode = XFS_ILOCK_SHARED;
1000 lockmode = xfs_ilock_data_map_shared(ip);
1001 }
1002 1014
1003 if ((flags & IOMAP_NOWAIT) && !(ip->i_df.if_flags & XFS_IFEXTENTS)) { 1015 if (flags & IOMAP_NOWAIT) {
1004 error = -EAGAIN; 1016 if (!(ip->i_df.if_flags & XFS_IFEXTENTS))
1005 goto out_unlock; 1017 return -EAGAIN;
1018 if (!xfs_ilock_nowait(ip, lockmode))
1019 return -EAGAIN;
1020 } else {
1021 xfs_ilock(ip, lockmode);
1006 } 1022 }
1007 1023
1008 ASSERT(offset <= mp->m_super->s_maxbytes); 1024 ASSERT(offset <= mp->m_super->s_maxbytes);
@@ -1024,7 +1040,9 @@ xfs_file_iomap_begin(
1024 goto out_unlock; 1040 goto out_unlock;
1025 } 1041 }
1026 1042
1027 if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { 1043 if (xfs_is_reflink_inode(ip) &&
1044 ((flags & IOMAP_WRITE) ||
1045 ((flags & IOMAP_ZERO) && needs_cow_for_zeroing(&imap, nimaps)))) {
1028 if (flags & IOMAP_DIRECT) { 1046 if (flags & IOMAP_DIRECT) {
1029 /* 1047 /*
1030 * A reflinked inode will result in CoW alloc. 1048 * A reflinked inode will result in CoW alloc.