|
@@ -224,7 +224,7 @@ xfs_read(
|
|
mp->m_rtdev_targp : mp->m_ddev_targp;
|
|
mp->m_rtdev_targp : mp->m_ddev_targp;
|
|
if ((*offset & target->bt_smask) ||
|
|
if ((*offset & target->bt_smask) ||
|
|
(size & target->bt_smask)) {
|
|
(size & target->bt_smask)) {
|
|
- if (*offset == ip->i_d.di_size) {
|
|
|
|
|
|
+ if (*offset == ip->i_size) {
|
|
return (0);
|
|
return (0);
|
|
}
|
|
}
|
|
return -XFS_ERROR(EINVAL);
|
|
return -XFS_ERROR(EINVAL);
|
|
@@ -387,9 +387,10 @@ xfs_splice_write(
|
|
{
|
|
{
|
|
xfs_inode_t *ip = XFS_BHVTOI(bdp);
|
|
xfs_inode_t *ip = XFS_BHVTOI(bdp);
|
|
xfs_mount_t *mp = ip->i_mount;
|
|
xfs_mount_t *mp = ip->i_mount;
|
|
|
|
+ xfs_iocore_t *io = &ip->i_iocore;
|
|
ssize_t ret;
|
|
ssize_t ret;
|
|
struct inode *inode = outfilp->f_mapping->host;
|
|
struct inode *inode = outfilp->f_mapping->host;
|
|
- xfs_fsize_t isize;
|
|
|
|
|
|
+ xfs_fsize_t isize, new_size;
|
|
|
|
|
|
XFS_STATS_INC(xs_write_calls);
|
|
XFS_STATS_INC(xs_write_calls);
|
|
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
|
|
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
|
|
@@ -410,6 +411,14 @@ xfs_splice_write(
|
|
return -error;
|
|
return -error;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ new_size = *ppos + count;
|
|
|
|
+
|
|
|
|
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
|
|
|
|
+ if (new_size > ip->i_size)
|
|
|
|
+ io->io_new_size = new_size;
|
|
|
|
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
|
|
|
+
|
|
xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore,
|
|
xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore,
|
|
pipe, count, *ppos, ioflags);
|
|
pipe, count, *ppos, ioflags);
|
|
ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags);
|
|
ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags);
|
|
@@ -420,14 +429,18 @@ xfs_splice_write(
|
|
if (unlikely(ret < 0 && ret != -EFAULT && *ppos > isize))
|
|
if (unlikely(ret < 0 && ret != -EFAULT && *ppos > isize))
|
|
*ppos = isize;
|
|
*ppos = isize;
|
|
|
|
|
|
- if (*ppos > ip->i_d.di_size) {
|
|
|
|
|
|
+ if (*ppos > ip->i_size) {
|
|
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
|
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
|
- if (*ppos > ip->i_d.di_size) {
|
|
|
|
- ip->i_d.di_size = *ppos;
|
|
|
|
- i_size_write(inode, *ppos);
|
|
|
|
- ip->i_update_core = 1;
|
|
|
|
- ip->i_update_size = 1;
|
|
|
|
- }
|
|
|
|
|
|
+ if (*ppos > ip->i_size)
|
|
|
|
+ ip->i_size = *ppos;
|
|
|
|
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (io->io_new_size) {
|
|
|
|
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
|
|
|
|
+ io->io_new_size = 0;
|
|
|
|
+ if (ip->i_d.di_size > ip->i_size)
|
|
|
|
+ ip->i_d.di_size = ip->i_size;
|
|
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
|
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
|
}
|
|
}
|
|
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
|
|
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
|
|
@@ -711,8 +724,6 @@ start:
|
|
goto out_unlock_mutex;
|
|
goto out_unlock_mutex;
|
|
}
|
|
}
|
|
|
|
|
|
- isize = i_size_read(inode);
|
|
|
|
-
|
|
|
|
if (ioflags & IO_ISDIRECT) {
|
|
if (ioflags & IO_ISDIRECT) {
|
|
xfs_buftarg_t *target =
|
|
xfs_buftarg_t *target =
|
|
(xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
|
|
(xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
|
|
@@ -723,7 +734,7 @@ start:
|
|
return XFS_ERROR(-EINVAL);
|
|
return XFS_ERROR(-EINVAL);
|
|
}
|
|
}
|
|
|
|
|
|
- if (!need_i_mutex && (VN_CACHED(vp) || pos > isize)) {
|
|
|
|
|
|
+ if (!need_i_mutex && (VN_CACHED(vp) || pos > xip->i_size)) {
|
|
xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
|
|
xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
|
|
iolock = XFS_IOLOCK_EXCL;
|
|
iolock = XFS_IOLOCK_EXCL;
|
|
locktype = VRWLOCK_WRITE;
|
|
locktype = VRWLOCK_WRITE;
|
|
@@ -735,7 +746,7 @@ start:
|
|
}
|
|
}
|
|
|
|
|
|
new_size = pos + count;
|
|
new_size = pos + count;
|
|
- if (new_size > isize)
|
|
|
|
|
|
+ if (new_size > xip->i_size)
|
|
io->io_new_size = new_size;
|
|
io->io_new_size = new_size;
|
|
|
|
|
|
if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
|
|
if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
|
|
@@ -751,8 +762,7 @@ start:
|
|
pos, count,
|
|
pos, count,
|
|
dmflags, &locktype);
|
|
dmflags, &locktype);
|
|
if (error) {
|
|
if (error) {
|
|
- xfs_iunlock(xip, iolock);
|
|
|
|
- goto out_unlock_mutex;
|
|
|
|
|
|
+ goto out_unlock_internal;
|
|
}
|
|
}
|
|
xfs_ilock(xip, XFS_ILOCK_EXCL);
|
|
xfs_ilock(xip, XFS_ILOCK_EXCL);
|
|
eventsent = 1;
|
|
eventsent = 1;
|
|
@@ -764,9 +774,8 @@ start:
|
|
* event prevents another call to XFS_SEND_DATA, which is
|
|
* event prevents another call to XFS_SEND_DATA, which is
|
|
* what allows the size to change in the first place.
|
|
* what allows the size to change in the first place.
|
|
*/
|
|
*/
|
|
- if ((file->f_flags & O_APPEND) && savedsize != isize) {
|
|
|
|
|
|
+ if ((file->f_flags & O_APPEND) && savedsize != xip->i_size)
|
|
goto start;
|
|
goto start;
|
|
- }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (likely(!(ioflags & IO_INVIS))) {
|
|
if (likely(!(ioflags & IO_INVIS))) {
|
|
@@ -784,11 +793,11 @@ start:
|
|
* to zero it out up to the new size.
|
|
* to zero it out up to the new size.
|
|
*/
|
|
*/
|
|
|
|
|
|
- if (pos > isize) {
|
|
|
|
- error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, isize);
|
|
|
|
|
|
+ if (pos > xip->i_size) {
|
|
|
|
+ error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, xip->i_size);
|
|
if (error) {
|
|
if (error) {
|
|
- xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
|
|
|
|
- goto out_unlock_mutex;
|
|
|
|
|
|
+ xfs_iunlock(xip, XFS_ILOCK_EXCL);
|
|
|
|
+ goto out_unlock_internal;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
xfs_iunlock(xip, XFS_ILOCK_EXCL);
|
|
xfs_iunlock(xip, XFS_ILOCK_EXCL);
|
|
@@ -808,8 +817,7 @@ start:
|
|
if (likely(!error))
|
|
if (likely(!error))
|
|
error = -remove_suid(file->f_path.dentry);
|
|
error = -remove_suid(file->f_path.dentry);
|
|
if (unlikely(error)) {
|
|
if (unlikely(error)) {
|
|
- xfs_iunlock(xip, iolock);
|
|
|
|
- goto out_unlock_mutex;
|
|
|
|
|
|
+ goto out_unlock_internal;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -879,12 +887,12 @@ retry:
|
|
error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp,
|
|
error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp,
|
|
DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL,
|
|
DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL,
|
|
0, 0, 0); /* Delay flag intentionally unused */
|
|
0, 0, 0); /* Delay flag intentionally unused */
|
|
- if (error)
|
|
|
|
- goto out_nounlocks;
|
|
|
|
if (need_i_mutex)
|
|
if (need_i_mutex)
|
|
mutex_lock(&inode->i_mutex);
|
|
mutex_lock(&inode->i_mutex);
|
|
xfs_rwlock(bdp, locktype);
|
|
xfs_rwlock(bdp, locktype);
|
|
- pos = xip->i_d.di_size;
|
|
|
|
|
|
+ if (error)
|
|
|
|
+ goto out_unlock_internal;
|
|
|
|
+ pos = xip->i_size;
|
|
ret = 0;
|
|
ret = 0;
|
|
goto retry;
|
|
goto retry;
|
|
}
|
|
}
|
|
@@ -893,14 +901,10 @@ retry:
|
|
if (unlikely(ret < 0 && ret != -EFAULT && *offset > isize))
|
|
if (unlikely(ret < 0 && ret != -EFAULT && *offset > isize))
|
|
*offset = isize;
|
|
*offset = isize;
|
|
|
|
|
|
- if (*offset > xip->i_d.di_size) {
|
|
|
|
|
|
+ if (*offset > xip->i_size) {
|
|
xfs_ilock(xip, XFS_ILOCK_EXCL);
|
|
xfs_ilock(xip, XFS_ILOCK_EXCL);
|
|
- if (*offset > xip->i_d.di_size) {
|
|
|
|
- xip->i_d.di_size = *offset;
|
|
|
|
- i_size_write(inode, *offset);
|
|
|
|
- xip->i_update_core = 1;
|
|
|
|
- xip->i_update_size = 1;
|
|
|
|
- }
|
|
|
|
|
|
+ if (*offset > xip->i_size)
|
|
|
|
+ xip->i_size = *offset;
|
|
xfs_iunlock(xip, XFS_ILOCK_EXCL);
|
|
xfs_iunlock(xip, XFS_ILOCK_EXCL);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -922,16 +926,31 @@ retry:
|
|
|
|
|
|
error = sync_page_range(inode, mapping, pos, ret);
|
|
error = sync_page_range(inode, mapping, pos, ret);
|
|
if (!error)
|
|
if (!error)
|
|
- error = ret;
|
|
|
|
- return error;
|
|
|
|
|
|
+ error = -ret;
|
|
|
|
+ if (need_i_mutex)
|
|
|
|
+ mutex_lock(&inode->i_mutex);
|
|
|
|
+ xfs_rwlock(bdp, locktype);
|
|
}
|
|
}
|
|
|
|
|
|
out_unlock_internal:
|
|
out_unlock_internal:
|
|
|
|
+ if (io->io_new_size) {
|
|
|
|
+ xfs_ilock(xip, XFS_ILOCK_EXCL);
|
|
|
|
+ io->io_new_size = 0;
|
|
|
|
+ /*
|
|
|
|
+ * If this was a direct or synchronous I/O that failed (such
|
|
|
|
+ * as ENOSPC) then part of the I/O may have been written to
|
|
|
|
+ * disk before the error occured. In this case the on-disk
|
|
|
|
+ * file size may have been adjusted beyond the in-memory file
|
|
|
|
+ * size and now needs to be truncated back.
|
|
|
|
+ */
|
|
|
|
+ if (xip->i_d.di_size > xip->i_size)
|
|
|
|
+ xip->i_d.di_size = xip->i_size;
|
|
|
|
+ xfs_iunlock(xip, XFS_ILOCK_EXCL);
|
|
|
|
+ }
|
|
xfs_rwunlock(bdp, locktype);
|
|
xfs_rwunlock(bdp, locktype);
|
|
out_unlock_mutex:
|
|
out_unlock_mutex:
|
|
if (need_i_mutex)
|
|
if (need_i_mutex)
|
|
mutex_unlock(&inode->i_mutex);
|
|
mutex_unlock(&inode->i_mutex);
|
|
- out_nounlocks:
|
|
|
|
return -error;
|
|
return -error;
|
|
}
|
|
}
|
|
|
|
|