|
@@ -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:
|