Skip to content

Commit

Permalink
[XFS] Fix race in xfs_write() b/w dmapi callout and direct I/O checks.
Browse files Browse the repository at this point in the history
In xfs_write() the iolock is dropped and reacquired in XFS_SEND_DATA()
which means that the file could change from not-cached to cached and we
need to redo the direct I/O checks. We should also redo the direct I/O
checks when the file size changes regardless if O_APPEND is set or not.

SGI-PV: 963483
SGI-Modid: xfs-linux-melb:xfs-kern:28440a

Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
  • Loading branch information
Lachlan McIlroy authored and Tim Shimmin committed May 8, 2007
1 parent 3a02ee1 commit 71dfd5a
Showing 1 changed file with 26 additions and 27 deletions.
53 changes: 26 additions & 27 deletions fs/xfs/linux-2.6/xfs_lrw.c
Original file line number Diff line number Diff line change
Expand Up @@ -724,34 +724,8 @@ xfs_write(
goto out_unlock_mutex;
}

if (ioflags & IO_ISDIRECT) {
xfs_buftarg_t *target =
(xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
mp->m_rtdev_targp : mp->m_ddev_targp;

if ((pos & target->bt_smask) || (count & target->bt_smask)) {
xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
return XFS_ERROR(-EINVAL);
}

if (!need_i_mutex && (VN_CACHED(vp) || pos > xip->i_size)) {
xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
iolock = XFS_IOLOCK_EXCL;
locktype = VRWLOCK_WRITE;
need_i_mutex = 1;
mutex_lock(&inode->i_mutex);
xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);
goto start;
}
}

new_size = pos + count;
if (new_size > xip->i_size)
io->io_new_size = new_size;

if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
!(ioflags & IO_INVIS) && !eventsent)) {
loff_t savedsize = pos;
int dmflags = FILP_DELAY_FLAG(file);

if (need_i_mutex)
Expand All @@ -774,10 +748,35 @@ xfs_write(
* event prevents another call to XFS_SEND_DATA, which is
* what allows the size to change in the first place.
*/
if ((file->f_flags & O_APPEND) && savedsize != xip->i_size)
if ((file->f_flags & O_APPEND) && pos != xip->i_size)
goto start;
}

if (ioflags & IO_ISDIRECT) {
xfs_buftarg_t *target =
(xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
mp->m_rtdev_targp : mp->m_ddev_targp;

if ((pos & target->bt_smask) || (count & target->bt_smask)) {
xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
return XFS_ERROR(-EINVAL);
}

if (!need_i_mutex && (VN_CACHED(vp) || pos > xip->i_size)) {
xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
iolock = XFS_IOLOCK_EXCL;
locktype = VRWLOCK_WRITE;
need_i_mutex = 1;
mutex_lock(&inode->i_mutex);
xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);
goto start;
}
}

new_size = pos + count;
if (new_size > xip->i_size)
io->io_new_size = new_size;

if (likely(!(ioflags & IO_INVIS))) {
file_update_time(file);
xfs_ichgtime_fast(xip, inode,
Expand Down

0 comments on commit 71dfd5a

Please sign in to comment.