Skip to content

Commit

Permalink
xfs: Factor xfs_seek_hole_data into helper
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Dave Chinner <[email protected]>
Signed-off-by: Dave Chinner <[email protected]>
  • Loading branch information
Eric Sandeen authored and dchinner committed Feb 8, 2016
1 parent 4d4d952 commit 8aa7d37
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 25 deletions.
82 changes: 57 additions & 25 deletions fs/xfs/xfs_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1337,54 +1337,54 @@ xfs_find_get_desired_pgoff(
return found;
}

STATIC loff_t
xfs_seek_hole_data(
struct file *file,
/*
* caller must lock inode with xfs_ilock_data_map_shared,
* 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 end,
int whence)
{
struct inode *inode = file->f_mapping->host;
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
loff_t uninitialized_var(offset);
xfs_fsize_t isize;
xfs_fileoff_t fsbno;
xfs_filblks_t end;
uint lock;
xfs_filblks_t lastbno;
int error;

if (XFS_FORCED_SHUTDOWN(mp))
return -EIO;

lock = xfs_ilock_data_map_shared(ip);

isize = i_size_read(inode);
if (start >= isize) {
if (start >= end) {
error = -ENXIO;
goto out_unlock;
goto out_error;
}

/*
* Try to read extents from the first block indicated
* by fsbno to the end block of the file.
*/
fsbno = XFS_B_TO_FSBT(mp, start);
end = XFS_B_TO_FSB(mp, isize);
lastbno = XFS_B_TO_FSB(mp, end);

for (;;) {
struct xfs_bmbt_irec map[2];
int nmap = 2;
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);
if (error)
goto out_unlock;
goto out_error;

/* No extents at given offset, must be beyond EOF */
if (nmap == 0) {
error = -ENXIO;
goto out_unlock;
goto out_error;
}

for (i = 0; i < nmap; i++) {
Expand Down Expand Up @@ -1426,15 +1426,15 @@ xfs_seek_hole_data(
* hole at the end of any file).
*/
if (whence == SEEK_HOLE) {
offset = isize;
offset = end;
break;
}
/*
* If we were looking for data, it's nowhere to be found
*/
ASSERT(whence == SEEK_DATA);
error = -ENXIO;
goto out_unlock;
goto out_error;
}

ASSERT(i > 1);
Expand All @@ -1445,14 +1445,14 @@ xfs_seek_hole_data(
*/
fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount;
start = XFS_FSB_TO_B(mp, fsbno);
if (start >= isize) {
if (start >= end) {
if (whence == SEEK_HOLE) {
offset = isize;
offset = end;
break;
}
ASSERT(whence == SEEK_DATA);
error = -ENXIO;
goto out_unlock;
goto out_error;
}
}

Expand All @@ -1464,7 +1464,39 @@ xfs_seek_hole_data(
* situation in particular.
*/
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);

out_unlock:
Expand Down
2 changes: 2 additions & 0 deletions fs/xfs/xfs_inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
xfs_fsize_t isize, bool *did_zeroing);
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 */
Expand Down

0 comments on commit 8aa7d37

Please sign in to comment.