aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_file.c
diff options
context:
space:
mode:
authorJeff Liu <jeff.liu@oracle.com>2012-08-21 05:12:18 -0400
committerBen Myers <bpm@sgi.com>2012-08-24 14:57:10 -0400
commitb686d1f79acb65c6a34473c15fcfa2ee54aed8e2 (patch)
treebd3e600ce359833dec65b9d64f29e7ce4c54ce87 /fs/xfs/xfs_file.c
parent52f1acc8b56a333fbc7218711c3fa2fb3bf78b92 (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/xfs_file.c')
-rw-r--r--fs/xfs/xfs_file.c78
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
1373out:
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