Skip to content

Commit b686d1f

Browse files
pibrochBen Myers
authored andcommitted
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 <[email protected]> Reviewed-by: Mark Tinguely <[email protected]> Reviewed-by: Dave Chinner <[email protected]> Signed-off-by: Ben Myers <[email protected]>
1 parent 52f1acc commit b686d1f

File tree

1 file changed

+67
-11
lines changed

1 file changed

+67
-11
lines changed

fs/xfs/xfs_file.c

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,9 +1289,9 @@ xfs_seek_hole(
12891289
struct xfs_inode *ip = XFS_I(inode);
12901290
struct xfs_mount *mp = ip->i_mount;
12911291
loff_t uninitialized_var(offset);
1292-
loff_t holeoff;
12931292
xfs_fsize_t isize;
12941293
xfs_fileoff_t fsbno;
1294+
xfs_filblks_t end;
12951295
uint lock;
12961296
int error;
12971297

@@ -1307,21 +1307,77 @@ xfs_seek_hole(
13071307
}
13081308

13091309
fsbno = XFS_B_TO_FSBT(mp, start);
1310-
error = xfs_bmap_first_unused(NULL, ip, 1, &fsbno, XFS_DATA_FORK);
1311-
if (error)
1312-
goto out_unlock;
1310+
end = XFS_B_TO_FSB(mp, isize);
1311+
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+
}
13131346

1314-
holeoff = XFS_FSB_TO_B(mp, fsbno);
1315-
if (holeoff <= start)
1316-
offset = start;
1317-
else {
13181347
/*
1319-
* xfs_bmap_first_unused() could return a value bigger than
1320-
* isize if there are no more holes past the supplied offset.
1348+
* map[0] contains data or its unwritten but contains
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).
13211353
*/
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+
}
13231371
}
13241372

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);
13251381
if (offset != file->f_pos)
13261382
file->f_pos = offset;
13271383

0 commit comments

Comments
 (0)