diff options
Diffstat (limited to 'fs/xfs/xfs_iomap.c')
-rw-r--r-- | fs/xfs/xfs_iomap.c | 75 |
1 files changed, 33 insertions, 42 deletions
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 1aa3abd67b36..41662fb14e87 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
@@ -162,7 +162,7 @@ xfs_iomap_write_direct( | |||
162 | xfs_fileoff_t last_fsb; | 162 | xfs_fileoff_t last_fsb; |
163 | xfs_filblks_t count_fsb, resaligned; | 163 | xfs_filblks_t count_fsb, resaligned; |
164 | xfs_fsblock_t firstfsb; | 164 | xfs_fsblock_t firstfsb; |
165 | xfs_extlen_t extsz, temp; | 165 | xfs_extlen_t extsz; |
166 | int nimaps; | 166 | int nimaps; |
167 | int quota_flag; | 167 | int quota_flag; |
168 | int rt; | 168 | int rt; |
@@ -203,14 +203,7 @@ xfs_iomap_write_direct( | |||
203 | } | 203 | } |
204 | count_fsb = last_fsb - offset_fsb; | 204 | count_fsb = last_fsb - offset_fsb; |
205 | ASSERT(count_fsb > 0); | 205 | ASSERT(count_fsb > 0); |
206 | 206 | resaligned = xfs_aligned_fsb_count(offset_fsb, count_fsb, extsz); | |
207 | resaligned = count_fsb; | ||
208 | if (unlikely(extsz)) { | ||
209 | if ((temp = do_mod(offset_fsb, extsz))) | ||
210 | resaligned += temp; | ||
211 | if ((temp = do_mod(resaligned, extsz))) | ||
212 | resaligned += extsz - temp; | ||
213 | } | ||
214 | 207 | ||
215 | if (unlikely(rt)) { | 208 | if (unlikely(rt)) { |
216 | resrtextents = qblocks = resaligned; | 209 | resrtextents = qblocks = resaligned; |
@@ -685,7 +678,7 @@ xfs_iomap_write_allocate( | |||
685 | int nres; | 678 | int nres; |
686 | 679 | ||
687 | if (whichfork == XFS_COW_FORK) | 680 | if (whichfork == XFS_COW_FORK) |
688 | flags |= XFS_BMAPI_COWFORK; | 681 | flags |= XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC; |
689 | 682 | ||
690 | /* | 683 | /* |
691 | * Make sure that the dquots are there. | 684 | * Make sure that the dquots are there. |
@@ -1002,47 +995,31 @@ xfs_file_iomap_begin( | |||
1002 | offset_fsb = XFS_B_TO_FSBT(mp, offset); | 995 | offset_fsb = XFS_B_TO_FSBT(mp, offset); |
1003 | end_fsb = XFS_B_TO_FSB(mp, offset + length); | 996 | end_fsb = XFS_B_TO_FSB(mp, offset + length); |
1004 | 997 | ||
1005 | if (xfs_is_reflink_inode(ip) && | ||
1006 | (flags & IOMAP_WRITE) && (flags & IOMAP_DIRECT)) { | ||
1007 | shared = xfs_reflink_find_cow_mapping(ip, offset, &imap); | ||
1008 | if (shared) { | ||
1009 | xfs_iunlock(ip, lockmode); | ||
1010 | goto alloc_done; | ||
1011 | } | ||
1012 | ASSERT(!isnullstartblock(imap.br_startblock)); | ||
1013 | } | ||
1014 | |||
1015 | error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap, | 998 | error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap, |
1016 | &nimaps, 0); | 999 | &nimaps, 0); |
1017 | if (error) | 1000 | if (error) |
1018 | goto out_unlock; | 1001 | goto out_unlock; |
1019 | 1002 | ||
1020 | if ((flags & IOMAP_REPORT) || | 1003 | if (flags & IOMAP_REPORT) { |
1021 | (xfs_is_reflink_inode(ip) && | ||
1022 | (flags & IOMAP_WRITE) && (flags & IOMAP_DIRECT))) { | ||
1023 | /* Trim the mapping to the nearest shared extent boundary. */ | 1004 | /* Trim the mapping to the nearest shared extent boundary. */ |
1024 | error = xfs_reflink_trim_around_shared(ip, &imap, &shared, | 1005 | error = xfs_reflink_trim_around_shared(ip, &imap, &shared, |
1025 | &trimmed); | 1006 | &trimmed); |
1026 | if (error) | 1007 | if (error) |
1027 | goto out_unlock; | 1008 | goto out_unlock; |
1028 | |||
1029 | /* | ||
1030 | * We're here because we're trying to do a directio write to a | ||
1031 | * region that isn't aligned to a filesystem block. If the | ||
1032 | * extent is shared, fall back to buffered mode to handle the | ||
1033 | * RMW. | ||
1034 | */ | ||
1035 | if (!(flags & IOMAP_REPORT) && shared) { | ||
1036 | trace_xfs_reflink_bounce_dio_write(ip, &imap); | ||
1037 | error = -EREMCHG; | ||
1038 | goto out_unlock; | ||
1039 | } | ||
1040 | } | 1009 | } |
1041 | 1010 | ||
1042 | if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { | 1011 | if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { |
1043 | error = xfs_reflink_reserve_cow(ip, &imap, &shared); | 1012 | if (flags & IOMAP_DIRECT) { |
1044 | if (error) | 1013 | /* may drop and re-acquire the ilock */ |
1045 | goto out_unlock; | 1014 | error = xfs_reflink_allocate_cow(ip, &imap, &shared, |
1015 | &lockmode); | ||
1016 | if (error) | ||
1017 | goto out_unlock; | ||
1018 | } else { | ||
1019 | error = xfs_reflink_reserve_cow(ip, &imap, &shared); | ||
1020 | if (error) | ||
1021 | goto out_unlock; | ||
1022 | } | ||
1046 | 1023 | ||
1047 | end_fsb = imap.br_startoff + imap.br_blockcount; | 1024 | end_fsb = imap.br_startoff + imap.br_blockcount; |
1048 | length = XFS_FSB_TO_B(mp, end_fsb) - offset; | 1025 | length = XFS_FSB_TO_B(mp, end_fsb) - offset; |
@@ -1071,7 +1048,6 @@ xfs_file_iomap_begin( | |||
1071 | if (error) | 1048 | if (error) |
1072 | return error; | 1049 | return error; |
1073 | 1050 | ||
1074 | alloc_done: | ||
1075 | iomap->flags = IOMAP_F_NEW; | 1051 | iomap->flags = IOMAP_F_NEW; |
1076 | trace_xfs_iomap_alloc(ip, offset, length, 0, &imap); | 1052 | trace_xfs_iomap_alloc(ip, offset, length, 0, &imap); |
1077 | } else { | 1053 | } else { |
@@ -1102,7 +1078,19 @@ xfs_file_iomap_end_delalloc( | |||
1102 | xfs_fileoff_t end_fsb; | 1078 | xfs_fileoff_t end_fsb; |
1103 | int error = 0; | 1079 | int error = 0; |
1104 | 1080 | ||
1105 | start_fsb = XFS_B_TO_FSB(mp, offset + written); | 1081 | /* behave as if the write failed if drop writes is enabled */ |
1082 | if (xfs_mp_drop_writes(mp)) | ||
1083 | written = 0; | ||
1084 | |||
1085 | /* | ||
1086 | * start_fsb refers to the first unused block after a short write. If | ||
1087 | * nothing was written, round offset down to point at the first block in | ||
1088 | * the range. | ||
1089 | */ | ||
1090 | if (unlikely(!written)) | ||
1091 | start_fsb = XFS_B_TO_FSBT(mp, offset); | ||
1092 | else | ||
1093 | start_fsb = XFS_B_TO_FSB(mp, offset + written); | ||
1106 | end_fsb = XFS_B_TO_FSB(mp, offset + length); | 1094 | end_fsb = XFS_B_TO_FSB(mp, offset + length); |
1107 | 1095 | ||
1108 | /* | 1096 | /* |
@@ -1114,6 +1102,9 @@ xfs_file_iomap_end_delalloc( | |||
1114 | * blocks in the range, they are ours. | 1102 | * blocks in the range, they are ours. |
1115 | */ | 1103 | */ |
1116 | if (start_fsb < end_fsb) { | 1104 | if (start_fsb < end_fsb) { |
1105 | truncate_pagecache_range(VFS_I(ip), XFS_FSB_TO_B(mp, start_fsb), | ||
1106 | XFS_FSB_TO_B(mp, end_fsb) - 1); | ||
1107 | |||
1117 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 1108 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
1118 | error = xfs_bmap_punch_delalloc_range(ip, start_fsb, | 1109 | error = xfs_bmap_punch_delalloc_range(ip, start_fsb, |
1119 | end_fsb - start_fsb); | 1110 | end_fsb - start_fsb); |
@@ -1144,7 +1135,7 @@ xfs_file_iomap_end( | |||
1144 | return 0; | 1135 | return 0; |
1145 | } | 1136 | } |
1146 | 1137 | ||
1147 | struct iomap_ops xfs_iomap_ops = { | 1138 | const struct iomap_ops xfs_iomap_ops = { |
1148 | .iomap_begin = xfs_file_iomap_begin, | 1139 | .iomap_begin = xfs_file_iomap_begin, |
1149 | .iomap_end = xfs_file_iomap_end, | 1140 | .iomap_end = xfs_file_iomap_end, |
1150 | }; | 1141 | }; |
@@ -1190,6 +1181,6 @@ out_unlock: | |||
1190 | return error; | 1181 | return error; |
1191 | } | 1182 | } |
1192 | 1183 | ||
1193 | struct iomap_ops xfs_xattr_iomap_ops = { | 1184 | const struct iomap_ops xfs_xattr_iomap_ops = { |
1194 | .iomap_begin = xfs_xattr_iomap_begin, | 1185 | .iomap_begin = xfs_xattr_iomap_begin, |
1195 | }; | 1186 | }; |