diff options
author | Jeff Liu <jeff.liu@oracle.com> | 2012-08-21 05:12:07 -0400 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2012-08-24 14:56:29 -0400 |
commit | 52f1acc8b56a333fbc7218711c3fa2fb3bf78b92 (patch) | |
tree | b918fef95d2605eadd216ceae1376bd0d8107c63 /fs | |
parent | d126d43f631f996daeee5006714fed914be32368 (diff) |
xfs: xfs_seek_data() refinement with unwritten extents check up from page cache
xfs_seek_data() refinement with unwritten extents check up from page cache.
Signed-off-by: Jie Liu <jeff.liu@oracle.com>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_file.c | 72 |
1 files changed, 54 insertions, 18 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index d78a746b6c7..3f9107431df 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -1186,8 +1186,6 @@ xfs_seek_data( | |||
1186 | struct inode *inode = file->f_mapping->host; | 1186 | struct inode *inode = file->f_mapping->host; |
1187 | struct xfs_inode *ip = XFS_I(inode); | 1187 | struct xfs_inode *ip = XFS_I(inode); |
1188 | struct xfs_mount *mp = ip->i_mount; | 1188 | struct xfs_mount *mp = ip->i_mount; |
1189 | struct xfs_bmbt_irec map[2]; | ||
1190 | int nmap = 2; | ||
1191 | loff_t uninitialized_var(offset); | 1189 | loff_t uninitialized_var(offset); |
1192 | xfs_fsize_t isize; | 1190 | xfs_fsize_t isize; |
1193 | xfs_fileoff_t fsbno; | 1191 | xfs_fileoff_t fsbno; |
@@ -1203,36 +1201,74 @@ xfs_seek_data( | |||
1203 | goto out_unlock; | 1201 | goto out_unlock; |
1204 | } | 1202 | } |
1205 | 1203 | ||
1206 | fsbno = XFS_B_TO_FSBT(mp, start); | ||
1207 | |||
1208 | /* | 1204 | /* |
1209 | * Try to read extents from the first block indicated | 1205 | * Try to read extents from the first block indicated |
1210 | * by fsbno to the end block of the file. | 1206 | * by fsbno to the end block of the file. |
1211 | */ | 1207 | */ |
1208 | fsbno = XFS_B_TO_FSBT(mp, start); | ||
1212 | end = XFS_B_TO_FSB(mp, isize); | 1209 | end = XFS_B_TO_FSB(mp, isize); |
1210 | for (;;) { | ||
1211 | struct xfs_bmbt_irec map[2]; | ||
1212 | int nmap = 2; | ||
1213 | unsigned int i; | ||
1213 | 1214 | ||
1214 | error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap, | 1215 | error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap, |
1215 | XFS_BMAPI_ENTIRE); | 1216 | XFS_BMAPI_ENTIRE); |
1216 | if (error) | 1217 | if (error) |
1217 | goto out_unlock; | 1218 | goto out_unlock; |
1218 | 1219 | ||
1219 | /* | 1220 | /* No extents at given offset, must be beyond EOF */ |
1220 | * Treat unwritten extent as data extent since it might | 1221 | if (nmap == 0) { |
1221 | * contains dirty data in page cache. | 1222 | error = ENXIO; |
1222 | */ | 1223 | goto out_unlock; |
1223 | if (map[0].br_startblock != HOLESTARTBLOCK) { | 1224 | } |
1224 | offset = max_t(loff_t, start, | 1225 | |
1225 | XFS_FSB_TO_B(mp, map[0].br_startoff)); | 1226 | for (i = 0; i < nmap; i++) { |
1226 | } else { | 1227 | offset = max_t(loff_t, start, |
1228 | XFS_FSB_TO_B(mp, map[i].br_startoff)); | ||
1229 | |||
1230 | /* Landed in a data extent */ | ||
1231 | if (map[i].br_startblock == DELAYSTARTBLOCK || | ||
1232 | (map[i].br_state == XFS_EXT_NORM && | ||
1233 | !isnullstartblock(map[i].br_startblock))) | ||
1234 | goto out; | ||
1235 | |||
1236 | /* | ||
1237 | * Landed in an unwritten extent, try to search data | ||
1238 | * from page cache. | ||
1239 | */ | ||
1240 | if (map[i].br_state == XFS_EXT_UNWRITTEN) { | ||
1241 | if (xfs_find_get_desired_pgoff(inode, &map[i], | ||
1242 | DATA_OFF, &offset)) | ||
1243 | goto out; | ||
1244 | } | ||
1245 | } | ||
1246 | |||
1247 | /* | ||
1248 | * map[0] is hole or its an unwritten extent but | ||
1249 | * without data in page cache. Probably means that | ||
1250 | * we are reading after EOF if nothing in map[1]. | ||
1251 | */ | ||
1227 | if (nmap == 1) { | 1252 | if (nmap == 1) { |
1228 | error = ENXIO; | 1253 | error = ENXIO; |
1229 | goto out_unlock; | 1254 | goto out_unlock; |
1230 | } | 1255 | } |
1231 | 1256 | ||
1232 | offset = max_t(loff_t, start, | 1257 | ASSERT(i > 1); |
1233 | XFS_FSB_TO_B(mp, map[1].br_startoff)); | 1258 | |
1259 | /* | ||
1260 | * Nothing was found, proceed to the next round of search | ||
1261 | * if reading offset not beyond or hit EOF. | ||
1262 | */ | ||
1263 | fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; | ||
1264 | start = XFS_FSB_TO_B(mp, fsbno); | ||
1265 | if (start >= isize) { | ||
1266 | error = ENXIO; | ||
1267 | goto out_unlock; | ||
1268 | } | ||
1234 | } | 1269 | } |
1235 | 1270 | ||
1271 | out: | ||
1236 | if (offset != file->f_pos) | 1272 | if (offset != file->f_pos) |
1237 | file->f_pos = offset; | 1273 | file->f_pos = offset; |
1238 | 1274 | ||