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>
This commit is contained in:
parent
4d4d9523b4
commit
8aa7d37ebf
|
@ -1337,31 +1337,31 @@ out:
|
|||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1369,22 +1369,22 @@ xfs_seek_hole_data(
|
|||
* 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++) {
|
||||
|
@ -1426,7 +1426,7 @@ xfs_seek_hole_data(
|
|||
* hole at the end of any file).
|
||||
*/
|
||||
if (whence == SEEK_HOLE) {
|
||||
offset = isize;
|
||||
offset = end;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
|
@ -1434,7 +1434,7 @@ xfs_seek_hole_data(
|
|||
*/
|
||||
ASSERT(whence == SEEK_DATA);
|
||||
error = -ENXIO;
|
||||
goto out_unlock;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
ASSERT(i > 1);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1464,7 +1464,39 @@ out:
|
|||
* 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:
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue