diff options
author | Jeff Liu <jeff.liu@oracle.com> | 2012-08-21 05:12:18 -0400 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2012-08-24 14:57:10 -0400 |
commit | b686d1f79acb65c6a34473c15fcfa2ee54aed8e2 (patch) | |
tree | bd3e600ce359833dec65b9d64f29e7ce4c54ce87 /fs/xfs | |
parent | 52f1acc8b56a333fbc7218711c3fa2fb3bf78b92 (diff) |
xfs: xfs_seek_hole() refinement with hole searching from page cache for unwritten extents
xfs_seek_hole() refinement with hole searching from page cache for unwritten extent.
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/xfs')
-rw-r--r-- | fs/xfs/xfs_file.c | 78 |
1 files changed, 67 insertions, 11 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 3f9107431dfb..1eaeb8be3aae 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -1289,9 +1289,9 @@ xfs_seek_hole( | |||
1289 | struct xfs_inode *ip = XFS_I(inode); | 1289 | struct xfs_inode *ip = XFS_I(inode); |
1290 | struct xfs_mount *mp = ip->i_mount; | 1290 | struct xfs_mount *mp = ip->i_mount; |
1291 | loff_t uninitialized_var(offset); | 1291 | loff_t uninitialized_var(offset); |
1292 | loff_t holeoff; | ||
1293 | xfs_fsize_t isize; | 1292 | xfs_fsize_t isize; |
1294 | xfs_fileoff_t fsbno; | 1293 | xfs_fileoff_t fsbno; |
1294 | xfs_filblks_t end; | ||
1295 | uint lock; | 1295 | uint lock; |
1296 | int error; | 1296 | int error; |
1297 | 1297 | ||
@@ -1307,21 +1307,77 @@ xfs_seek_hole( | |||
1307 | } | 1307 | } |
1308 | 1308 | ||
1309 | fsbno = XFS_B_TO_FSBT(mp, start); | 1309 | fsbno = XFS_B_TO_FSBT(mp, start); |
1310 | error = xfs_bmap_first_unused(NULL, ip, 1, &fsbno, XFS_DATA_FORK); | 1310 | end = XFS_B_TO_FSB(mp, isize); |
1311 | if (error) | 1311 | |
1312 | goto out_unlock; | 1312 | for (;;) { |
1313 | struct xfs_bmbt_irec map[2]; | ||
1314 | int nmap = 2; | ||
1315 | unsigned int i; | ||
1316 | |||
1317 | error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap, | ||
1318 | XFS_BMAPI_ENTIRE); | ||
1319 | if (error) | ||
1320 | goto out_unlock; | ||
1321 | |||
1322 | /* No extents at given offset, must be beyond EOF */ | ||
1323 | if (nmap == 0) { | ||
1324 | error = ENXIO; | ||
1325 | goto out_unlock; | ||
1326 | } | ||
1327 | |||
1328 | for (i = 0; i < nmap; i++) { | ||
1329 | offset = max_t(loff_t, start, | ||
1330 | XFS_FSB_TO_B(mp, map[i].br_startoff)); | ||
1331 | |||
1332 | /* Landed in a hole */ | ||
1333 | if (map[i].br_startblock == HOLESTARTBLOCK) | ||
1334 | goto out; | ||
1335 | |||
1336 | /* | ||
1337 | * Landed in an unwritten extent, try to search hole | ||
1338 | * from page cache. | ||
1339 | */ | ||
1340 | if (map[i].br_state == XFS_EXT_UNWRITTEN) { | ||
1341 | if (xfs_find_get_desired_pgoff(inode, &map[i], | ||
1342 | HOLE_OFF, &offset)) | ||
1343 | goto out; | ||
1344 | } | ||
1345 | } | ||
1313 | 1346 | ||
1314 | holeoff = XFS_FSB_TO_B(mp, fsbno); | ||
1315 | if (holeoff <= start) | ||
1316 | offset = start; | ||
1317 | else { | ||
1318 | /* | 1347 | /* |
1319 | * xfs_bmap_first_unused() could return a value bigger than | 1348 | * map[0] contains data or its unwritten but contains |
1320 | * isize if there are no more holes past the supplied offset. | 1349 | * data in page cache, probably means that we are |
1350 | * reading after EOF. We should fix offset to point | ||
1351 | * to the end of the file(i.e., there is an implicit | ||
1352 | * hole at the end of any file). | ||
1321 | */ | 1353 | */ |
1322 | offset = min_t(loff_t, holeoff, isize); | 1354 | if (nmap == 1) { |
1355 | offset = isize; | ||
1356 | break; | ||
1357 | } | ||
1358 | |||
1359 | ASSERT(i > 1); | ||
1360 | |||
1361 | /* | ||
1362 | * Both mappings contains data, proceed to the next round of | ||
1363 | * search if the current reading offset not beyond or hit EOF. | ||
1364 | */ | ||
1365 | fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; | ||
1366 | start = XFS_FSB_TO_B(mp, fsbno); | ||
1367 | if (start >= isize) { | ||
1368 | offset = isize; | ||
1369 | break; | ||
1370 | } | ||
1323 | } | 1371 | } |
1324 | 1372 | ||
1373 | out: | ||
1374 | /* | ||
1375 | * At this point, we must have found a hole. However, the returned | ||
1376 | * offset may be bigger than the file size as it may be aligned to | ||
1377 | * page boundary for unwritten extents, we need to deal with this | ||
1378 | * situation in particular. | ||
1379 | */ | ||
1380 | offset = min_t(loff_t, offset, isize); | ||
1325 | if (offset != file->f_pos) | 1381 | if (offset != file->f_pos) |
1326 | file->f_pos = offset; | 1382 | file->f_pos = offset; |
1327 | 1383 | ||