diff options
-rw-r--r-- | fs/xfs/xfs_file.c | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_iomap.c | 86 | ||||
-rw-r--r-- | fs/xfs/xfs_iomap.h | 1 |
3 files changed, 89 insertions, 2 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index e47425071e65..1d07dcfbbff3 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -1068,10 +1068,10 @@ xfs_file_llseek( | |||
1068 | default: | 1068 | default: |
1069 | return generic_file_llseek(file, offset, whence); | 1069 | return generic_file_llseek(file, offset, whence); |
1070 | case SEEK_HOLE: | 1070 | case SEEK_HOLE: |
1071 | offset = iomap_seek_hole(inode, offset, &xfs_iomap_ops); | 1071 | offset = iomap_seek_hole(inode, offset, &xfs_seek_iomap_ops); |
1072 | break; | 1072 | break; |
1073 | case SEEK_DATA: | 1073 | case SEEK_DATA: |
1074 | offset = iomap_seek_data(inode, offset, &xfs_iomap_ops); | 1074 | offset = iomap_seek_data(inode, offset, &xfs_seek_iomap_ops); |
1075 | break; | 1075 | break; |
1076 | } | 1076 | } |
1077 | 1077 | ||
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 284c5e68f695..df6eda336f17 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
@@ -1069,6 +1069,92 @@ const struct iomap_ops xfs_iomap_ops = { | |||
1069 | }; | 1069 | }; |
1070 | 1070 | ||
1071 | static int | 1071 | static int |
1072 | xfs_seek_iomap_begin( | ||
1073 | struct inode *inode, | ||
1074 | loff_t offset, | ||
1075 | loff_t length, | ||
1076 | unsigned flags, | ||
1077 | struct iomap *iomap) | ||
1078 | { | ||
1079 | struct xfs_inode *ip = XFS_I(inode); | ||
1080 | struct xfs_mount *mp = ip->i_mount; | ||
1081 | xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); | ||
1082 | xfs_fileoff_t end_fsb = XFS_B_TO_FSB(mp, offset + length); | ||
1083 | xfs_fileoff_t cow_fsb = NULLFILEOFF, data_fsb = NULLFILEOFF; | ||
1084 | struct xfs_iext_cursor icur; | ||
1085 | struct xfs_bmbt_irec imap, cmap; | ||
1086 | int error = 0; | ||
1087 | unsigned lockmode; | ||
1088 | |||
1089 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
1090 | return -EIO; | ||
1091 | |||
1092 | lockmode = xfs_ilock_data_map_shared(ip); | ||
1093 | if (!(ip->i_df.if_flags & XFS_IFEXTENTS)) { | ||
1094 | error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK); | ||
1095 | if (error) | ||
1096 | goto out_unlock; | ||
1097 | } | ||
1098 | |||
1099 | if (xfs_iext_lookup_extent(ip, &ip->i_df, offset_fsb, &icur, &imap)) { | ||
1100 | /* | ||
1101 | * If we found a data extent we are done. | ||
1102 | */ | ||
1103 | if (imap.br_startoff <= offset_fsb) | ||
1104 | goto done; | ||
1105 | data_fsb = imap.br_startoff; | ||
1106 | } else { | ||
1107 | /* | ||
1108 | * Fake a hole until the end of the file. | ||
1109 | */ | ||
1110 | data_fsb = min(XFS_B_TO_FSB(mp, offset + length), | ||
1111 | XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes)); | ||
1112 | } | ||
1113 | |||
1114 | /* | ||
1115 | * If a COW fork extent covers the hole, report it - capped to the next | ||
1116 | * data fork extent: | ||
1117 | */ | ||
1118 | if (xfs_inode_has_cow_data(ip) && | ||
1119 | xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &cmap)) | ||
1120 | cow_fsb = cmap.br_startoff; | ||
1121 | if (cow_fsb != NULLFILEOFF && cow_fsb <= offset_fsb) { | ||
1122 | if (data_fsb < cow_fsb + cmap.br_blockcount) | ||
1123 | end_fsb = min(end_fsb, data_fsb); | ||
1124 | xfs_trim_extent(&cmap, offset_fsb, end_fsb); | ||
1125 | error = xfs_bmbt_to_iomap(ip, iomap, &cmap, true); | ||
1126 | /* | ||
1127 | * This is a COW extent, so we must probe the page cache | ||
1128 | * because there could be dirty page cache being backed | ||
1129 | * by this extent. | ||
1130 | */ | ||
1131 | iomap->type = IOMAP_UNWRITTEN; | ||
1132 | goto out_unlock; | ||
1133 | } | ||
1134 | |||
1135 | /* | ||
1136 | * Else report a hole, capped to the next found data or COW extent. | ||
1137 | */ | ||
1138 | if (cow_fsb != NULLFILEOFF && cow_fsb < data_fsb) | ||
1139 | imap.br_blockcount = cow_fsb - offset_fsb; | ||
1140 | else | ||
1141 | imap.br_blockcount = data_fsb - offset_fsb; | ||
1142 | imap.br_startoff = offset_fsb; | ||
1143 | imap.br_startblock = HOLESTARTBLOCK; | ||
1144 | imap.br_state = XFS_EXT_NORM; | ||
1145 | done: | ||
1146 | xfs_trim_extent(&imap, offset_fsb, end_fsb); | ||
1147 | error = xfs_bmbt_to_iomap(ip, iomap, &imap, false); | ||
1148 | out_unlock: | ||
1149 | xfs_iunlock(ip, lockmode); | ||
1150 | return error; | ||
1151 | } | ||
1152 | |||
1153 | const struct iomap_ops xfs_seek_iomap_ops = { | ||
1154 | .iomap_begin = xfs_seek_iomap_begin, | ||
1155 | }; | ||
1156 | |||
1157 | static int | ||
1072 | xfs_xattr_iomap_begin( | 1158 | xfs_xattr_iomap_begin( |
1073 | struct inode *inode, | 1159 | struct inode *inode, |
1074 | loff_t offset, | 1160 | loff_t offset, |
diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h index 37b584c3069b..5c2f6aa6d78f 100644 --- a/fs/xfs/xfs_iomap.h +++ b/fs/xfs/xfs_iomap.h | |||
@@ -40,6 +40,7 @@ xfs_aligned_fsb_count( | |||
40 | } | 40 | } |
41 | 41 | ||
42 | extern const struct iomap_ops xfs_iomap_ops; | 42 | extern const struct iomap_ops xfs_iomap_ops; |
43 | extern const struct iomap_ops xfs_seek_iomap_ops; | ||
43 | extern const struct iomap_ops xfs_xattr_iomap_ops; | 44 | extern const struct iomap_ops xfs_xattr_iomap_ops; |
44 | 45 | ||
45 | #endif /* __XFS_IOMAP_H__*/ | 46 | #endif /* __XFS_IOMAP_H__*/ |