diff options
author | Eric Sandeen <sandeen@redhat.com> | 2016-02-07 19:25:16 -0500 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2016-02-07 19:25:16 -0500 |
commit | 8aa7d37ebf2f0cfba1411acb34e7b40e73f653e7 (patch) | |
tree | d26e14d7b6d3ebd94c3c9347e6ac0dc608bb2f80 | |
parent | 4d4d9523b4ebbd5d97c8b2557c6ee2a3f90b6b3a (diff) |
xfs: Factor xfs_seek_hole_data into helper
Factor xfs_seek_hole_data into an unlocked helper which takes
an xfs inode rather than a file for internal use.
Also allow specification of "end" - the vfs lseek interface is
defined such that any offset past eof/i_size shall return -ENXIO,
but we will use this for quota code which does not maintain i_size,
and we want to be able to SEEK_DATA past i_size as well. So the
lseek path can send in i_size, and the quota code can determine
its own ending offset.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r-- | fs/xfs/xfs_file.c | 82 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.h | 2 |
2 files changed, 59 insertions, 25 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 52883ac3cf84..70a4b5a2802e 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -1337,31 +1337,31 @@ out: | |||
1337 | return found; | 1337 | return found; |
1338 | } | 1338 | } |
1339 | 1339 | ||
1340 | STATIC loff_t | 1340 | /* |
1341 | xfs_seek_hole_data( | 1341 | * caller must lock inode with xfs_ilock_data_map_shared, |
1342 | struct file *file, | 1342 | * can we craft an appropriate ASSERT? |
1343 | * | ||
1344 | * end is because the VFS-level lseek interface is defined such that any | ||
1345 | * offset past i_size shall return -ENXIO, but we use this for quota code | ||
1346 | * which does not maintain i_size, and we want to SEEK_DATA past i_size. | ||
1347 | */ | ||
1348 | loff_t | ||
1349 | __xfs_seek_hole_data( | ||
1350 | struct inode *inode, | ||
1343 | loff_t start, | 1351 | loff_t start, |
1352 | loff_t end, | ||
1344 | int whence) | 1353 | int whence) |
1345 | { | 1354 | { |
1346 | struct inode *inode = file->f_mapping->host; | ||
1347 | struct xfs_inode *ip = XFS_I(inode); | 1355 | struct xfs_inode *ip = XFS_I(inode); |
1348 | struct xfs_mount *mp = ip->i_mount; | 1356 | struct xfs_mount *mp = ip->i_mount; |
1349 | loff_t uninitialized_var(offset); | 1357 | loff_t uninitialized_var(offset); |
1350 | xfs_fsize_t isize; | ||
1351 | xfs_fileoff_t fsbno; | 1358 | xfs_fileoff_t fsbno; |
1352 | xfs_filblks_t end; | 1359 | xfs_filblks_t lastbno; |
1353 | uint lock; | ||
1354 | int error; | 1360 | int error; |
1355 | 1361 | ||
1356 | if (XFS_FORCED_SHUTDOWN(mp)) | 1362 | if (start >= end) { |
1357 | return -EIO; | ||
1358 | |||
1359 | lock = xfs_ilock_data_map_shared(ip); | ||
1360 | |||
1361 | isize = i_size_read(inode); | ||
1362 | if (start >= isize) { | ||
1363 | error = -ENXIO; | 1363 | error = -ENXIO; |
1364 | goto out_unlock; | 1364 | goto out_error; |
1365 | } | 1365 | } |
1366 | 1366 | ||
1367 | /* | 1367 | /* |
@@ -1369,22 +1369,22 @@ xfs_seek_hole_data( | |||
1369 | * by fsbno to the end block of the file. | 1369 | * by fsbno to the end block of the file. |
1370 | */ | 1370 | */ |
1371 | fsbno = XFS_B_TO_FSBT(mp, start); | 1371 | fsbno = XFS_B_TO_FSBT(mp, start); |
1372 | end = XFS_B_TO_FSB(mp, isize); | 1372 | lastbno = XFS_B_TO_FSB(mp, end); |
1373 | 1373 | ||
1374 | for (;;) { | 1374 | for (;;) { |
1375 | struct xfs_bmbt_irec map[2]; | 1375 | struct xfs_bmbt_irec map[2]; |
1376 | int nmap = 2; | 1376 | int nmap = 2; |
1377 | unsigned int i; | 1377 | unsigned int i; |
1378 | 1378 | ||
1379 | error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap, | 1379 | error = xfs_bmapi_read(ip, fsbno, lastbno - fsbno, map, &nmap, |
1380 | XFS_BMAPI_ENTIRE); | 1380 | XFS_BMAPI_ENTIRE); |
1381 | if (error) | 1381 | if (error) |
1382 | goto out_unlock; | 1382 | goto out_error; |
1383 | 1383 | ||
1384 | /* No extents at given offset, must be beyond EOF */ | 1384 | /* No extents at given offset, must be beyond EOF */ |
1385 | if (nmap == 0) { | 1385 | if (nmap == 0) { |
1386 | error = -ENXIO; | 1386 | error = -ENXIO; |
1387 | goto out_unlock; | 1387 | goto out_error; |
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | for (i = 0; i < nmap; i++) { | 1390 | for (i = 0; i < nmap; i++) { |
@@ -1426,7 +1426,7 @@ xfs_seek_hole_data( | |||
1426 | * hole at the end of any file). | 1426 | * hole at the end of any file). |
1427 | */ | 1427 | */ |
1428 | if (whence == SEEK_HOLE) { | 1428 | if (whence == SEEK_HOLE) { |
1429 | offset = isize; | 1429 | offset = end; |
1430 | break; | 1430 | break; |
1431 | } | 1431 | } |
1432 | /* | 1432 | /* |
@@ -1434,7 +1434,7 @@ xfs_seek_hole_data( | |||
1434 | */ | 1434 | */ |
1435 | ASSERT(whence == SEEK_DATA); | 1435 | ASSERT(whence == SEEK_DATA); |
1436 | error = -ENXIO; | 1436 | error = -ENXIO; |
1437 | goto out_unlock; | 1437 | goto out_error; |
1438 | } | 1438 | } |
1439 | 1439 | ||
1440 | ASSERT(i > 1); | 1440 | ASSERT(i > 1); |
@@ -1445,14 +1445,14 @@ xfs_seek_hole_data( | |||
1445 | */ | 1445 | */ |
1446 | fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; | 1446 | fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; |
1447 | start = XFS_FSB_TO_B(mp, fsbno); | 1447 | start = XFS_FSB_TO_B(mp, fsbno); |
1448 | if (start >= isize) { | 1448 | if (start >= end) { |
1449 | if (whence == SEEK_HOLE) { | 1449 | if (whence == SEEK_HOLE) { |
1450 | offset = isize; | 1450 | offset = end; |
1451 | break; | 1451 | break; |
1452 | } | 1452 | } |
1453 | ASSERT(whence == SEEK_DATA); | 1453 | ASSERT(whence == SEEK_DATA); |
1454 | error = -ENXIO; | 1454 | error = -ENXIO; |
1455 | goto out_unlock; | 1455 | goto out_error; |
1456 | } | 1456 | } |
1457 | } | 1457 | } |
1458 | 1458 | ||
@@ -1464,7 +1464,39 @@ out: | |||
1464 | * situation in particular. | 1464 | * situation in particular. |
1465 | */ | 1465 | */ |
1466 | if (whence == SEEK_HOLE) | 1466 | if (whence == SEEK_HOLE) |
1467 | offset = min_t(loff_t, offset, isize); | 1467 | offset = min_t(loff_t, offset, end); |
1468 | |||
1469 | return offset; | ||
1470 | |||
1471 | out_error: | ||
1472 | return error; | ||
1473 | } | ||
1474 | |||
1475 | STATIC loff_t | ||
1476 | xfs_seek_hole_data( | ||
1477 | struct file *file, | ||
1478 | loff_t start, | ||
1479 | int whence) | ||
1480 | { | ||
1481 | struct inode *inode = file->f_mapping->host; | ||
1482 | struct xfs_inode *ip = XFS_I(inode); | ||
1483 | struct xfs_mount *mp = ip->i_mount; | ||
1484 | uint lock; | ||
1485 | loff_t offset, end; | ||
1486 | int error = 0; | ||
1487 | |||
1488 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
1489 | return -EIO; | ||
1490 | |||
1491 | lock = xfs_ilock_data_map_shared(ip); | ||
1492 | |||
1493 | end = i_size_read(inode); | ||
1494 | offset = __xfs_seek_hole_data(inode, start, end, whence); | ||
1495 | if (offset < 0) { | ||
1496 | error = offset; | ||
1497 | goto out_unlock; | ||
1498 | } | ||
1499 | |||
1468 | offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); | 1500 | offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); |
1469 | 1501 | ||
1470 | out_unlock: | 1502 | out_unlock: |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index ca9e11989cbd..ed7e9339c7e9 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -437,6 +437,8 @@ int xfs_update_prealloc_flags(struct xfs_inode *ip, | |||
437 | int xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset, | 437 | int xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset, |
438 | xfs_fsize_t isize, bool *did_zeroing); | 438 | xfs_fsize_t isize, bool *did_zeroing); |
439 | int xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count); | 439 | int xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count); |
440 | loff_t __xfs_seek_hole_data(struct inode *inode, loff_t start, | ||
441 | loff_t eof, int whence); | ||
440 | 442 | ||
441 | 443 | ||
442 | /* from xfs_iops.c */ | 444 | /* from xfs_iops.c */ |