summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_file.c4
-rw-r--r--fs/xfs/xfs_iomap.c86
-rw-r--r--fs/xfs/xfs_iomap.h1
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
1071static int 1071static int
1072xfs_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;
1145done:
1146 xfs_trim_extent(&imap, offset_fsb, end_fsb);
1147 error = xfs_bmbt_to_iomap(ip, iomap, &imap, false);
1148out_unlock:
1149 xfs_iunlock(ip, lockmode);
1150 return error;
1151}
1152
1153const struct iomap_ops xfs_seek_iomap_ops = {
1154 .iomap_begin = xfs_seek_iomap_begin,
1155};
1156
1157static int
1072xfs_xattr_iomap_begin( 1158xfs_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
42extern const struct iomap_ops xfs_iomap_ops; 42extern const struct iomap_ops xfs_iomap_ops;
43extern const struct iomap_ops xfs_seek_iomap_ops;
43extern const struct iomap_ops xfs_xattr_iomap_ops; 44extern const struct iomap_ops xfs_xattr_iomap_ops;
44 45
45#endif /* __XFS_IOMAP_H__*/ 46#endif /* __XFS_IOMAP_H__*/