[XFS] Fix race in xfs_write() b/w dmapi callout and direct I/O checks.
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>
This commit is contained in:
parent
3a02ee1828
commit
71dfd5a396
|
@ -724,6 +724,34 @@ start:
|
|||
goto out_unlock_mutex;
|
||||
}
|
||||
|
||||
if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
|
||||
!(ioflags & IO_INVIS) && !eventsent)) {
|
||||
int dmflags = FILP_DELAY_FLAG(file);
|
||||
|
||||
if (need_i_mutex)
|
||||
dmflags |= DM_FLAGS_IMUX;
|
||||
|
||||
xfs_iunlock(xip, XFS_ILOCK_EXCL);
|
||||
error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, vp,
|
||||
pos, count,
|
||||
dmflags, &locktype);
|
||||
if (error) {
|
||||
goto out_unlock_internal;
|
||||
}
|
||||
xfs_ilock(xip, XFS_ILOCK_EXCL);
|
||||
eventsent = 1;
|
||||
|
||||
/*
|
||||
* The iolock was dropped and reacquired in XFS_SEND_DATA
|
||||
* so we have to recheck the size when appending.
|
||||
* We will only "goto start;" once, since having sent the
|
||||
* 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) && pos != xip->i_size)
|
||||
goto start;
|
||||
}
|
||||
|
||||
if (ioflags & IO_ISDIRECT) {
|
||||
xfs_buftarg_t *target =
|
||||
(xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
|
||||
|
@ -749,35 +777,6 @@ start:
|
|||
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)
|
||||
dmflags |= DM_FLAGS_IMUX;
|
||||
|
||||
xfs_iunlock(xip, XFS_ILOCK_EXCL);
|
||||
error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, vp,
|
||||
pos, count,
|
||||
dmflags, &locktype);
|
||||
if (error) {
|
||||
goto out_unlock_internal;
|
||||
}
|
||||
xfs_ilock(xip, XFS_ILOCK_EXCL);
|
||||
eventsent = 1;
|
||||
|
||||
/*
|
||||
* The iolock was dropped and reacquired in XFS_SEND_DATA
|
||||
* so we have to recheck the size when appending.
|
||||
* We will only "goto start;" once, since having sent the
|
||||
* 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)
|
||||
goto start;
|
||||
}
|
||||
|
||||
if (likely(!(ioflags & IO_INVIS))) {
|
||||
file_update_time(file);
|
||||
xfs_ichgtime_fast(xip, inode,
|
||||
|
|
Loading…
Reference in a new issue