Commit 8aa7d37e authored by Eric Sandeen's avatar Eric Sandeen Committed by Dave Chinner

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: default avatarEric Sandeen <sandeen@redhat.com>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent 4d4d9523
...@@ -1337,31 +1337,31 @@ xfs_find_get_desired_pgoff( ...@@ -1337,31 +1337,31 @@ xfs_find_get_desired_pgoff(
return found; return found;
} }
STATIC loff_t /*
xfs_seek_hole_data( * caller must lock inode with xfs_ilock_data_map_shared,
struct file *file, * can we craft an appropriate ASSERT?
*
* end is because the VFS-level lseek interface is defined such that any
* offset past i_size shall return -ENXIO, but we use this for quota code
* which does not maintain i_size, and we want to SEEK_DATA past i_size.
*/
loff_t
__xfs_seek_hole_data(
struct inode *inode,
loff_t start, loff_t start,
loff_t end,
int whence) int whence)
{ {
struct inode *inode = file->f_mapping->host;
struct xfs_inode *ip = XFS_I(inode); struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
loff_t uninitialized_var(offset); loff_t uninitialized_var(offset);
xfs_fsize_t isize;
xfs_fileoff_t fsbno; xfs_fileoff_t fsbno;
xfs_filblks_t end; xfs_filblks_t lastbno;
uint lock;
int error; int error;
if (XFS_FORCED_SHUTDOWN(mp)) if (start >= end) {
return -EIO;
lock = xfs_ilock_data_map_shared(ip);
isize = i_size_read(inode);
if (start >= isize) {
error = -ENXIO; error = -ENXIO;
goto out_unlock; goto out_error;
} }
/* /*
...@@ -1369,22 +1369,22 @@ xfs_seek_hole_data( ...@@ -1369,22 +1369,22 @@ xfs_seek_hole_data(
* by fsbno to the end block of the file. * by fsbno to the end block of the file.
*/ */
fsbno = XFS_B_TO_FSBT(mp, start); fsbno = XFS_B_TO_FSBT(mp, start);
end = XFS_B_TO_FSB(mp, isize); lastbno = XFS_B_TO_FSB(mp, end);
for (;;) { for (;;) {
struct xfs_bmbt_irec map[2]; struct xfs_bmbt_irec map[2];
int nmap = 2; int nmap = 2;
unsigned int i; unsigned int i;
error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap, error = xfs_bmapi_read(ip, fsbno, lastbno - fsbno, map, &nmap,
XFS_BMAPI_ENTIRE); XFS_BMAPI_ENTIRE);
if (error) if (error)
goto out_unlock; goto out_error;
/* No extents at given offset, must be beyond EOF */ /* No extents at given offset, must be beyond EOF */
if (nmap == 0) { if (nmap == 0) {
error = -ENXIO; error = -ENXIO;
goto out_unlock; goto out_error;
} }
for (i = 0; i < nmap; i++) { for (i = 0; i < nmap; i++) {
...@@ -1426,7 +1426,7 @@ xfs_seek_hole_data( ...@@ -1426,7 +1426,7 @@ xfs_seek_hole_data(
* hole at the end of any file). * hole at the end of any file).
*/ */
if (whence == SEEK_HOLE) { if (whence == SEEK_HOLE) {
offset = isize; offset = end;
break; break;
} }
/* /*
...@@ -1434,7 +1434,7 @@ xfs_seek_hole_data( ...@@ -1434,7 +1434,7 @@ xfs_seek_hole_data(
*/ */
ASSERT(whence == SEEK_DATA); ASSERT(whence == SEEK_DATA);
error = -ENXIO; error = -ENXIO;
goto out_unlock; goto out_error;
} }
ASSERT(i > 1); ASSERT(i > 1);
...@@ -1445,14 +1445,14 @@ xfs_seek_hole_data( ...@@ -1445,14 +1445,14 @@ xfs_seek_hole_data(
*/ */
fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount;
start = XFS_FSB_TO_B(mp, fsbno); start = XFS_FSB_TO_B(mp, fsbno);
if (start >= isize) { if (start >= end) {
if (whence == SEEK_HOLE) { if (whence == SEEK_HOLE) {
offset = isize; offset = end;
break; break;
} }
ASSERT(whence == SEEK_DATA); ASSERT(whence == SEEK_DATA);
error = -ENXIO; error = -ENXIO;
goto out_unlock; goto out_error;
} }
} }
...@@ -1464,7 +1464,39 @@ xfs_seek_hole_data( ...@@ -1464,7 +1464,39 @@ xfs_seek_hole_data(
* situation in particular. * situation in particular.
*/ */
if (whence == SEEK_HOLE) if (whence == SEEK_HOLE)
offset = min_t(loff_t, offset, isize); offset = min_t(loff_t, offset, end);
return offset;
out_error:
return error;
}
STATIC loff_t
xfs_seek_hole_data(
struct file *file,
loff_t start,
int whence)
{
struct inode *inode = file->f_mapping->host;
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
uint lock;
loff_t offset, end;
int error = 0;
if (XFS_FORCED_SHUTDOWN(mp))
return -EIO;
lock = xfs_ilock_data_map_shared(ip);
end = i_size_read(inode);
offset = __xfs_seek_hole_data(inode, start, end, whence);
if (offset < 0) {
error = offset;
goto out_unlock;
}
offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
out_unlock: out_unlock:
......
...@@ -437,6 +437,8 @@ int xfs_update_prealloc_flags(struct xfs_inode *ip, ...@@ -437,6 +437,8 @@ int xfs_update_prealloc_flags(struct xfs_inode *ip,
int xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset, int xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset,
xfs_fsize_t isize, bool *did_zeroing); xfs_fsize_t isize, bool *did_zeroing);
int xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count); int xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count);
loff_t __xfs_seek_hole_data(struct inode *inode, loff_t start,
loff_t eof, int whence);
/* from xfs_iops.c */ /* from xfs_iops.c */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment