[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 @@ xfs_write(
|
|||||||
goto out_unlock_mutex;
|
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) {
|
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) ?
|
||||||
@ -749,35 +777,6 @@ xfs_write(
|
|||||||
if (new_size > xip->i_size)
|
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) &&
|
|
||||||
!(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))) {
|
if (likely(!(ioflags & IO_INVIS))) {
|
||||||
file_update_time(file);
|
file_update_time(file);
|
||||||
xfs_ichgtime_fast(xip, inode,
|
xfs_ichgtime_fast(xip, inode,
|
||||||
|
Loading…
Reference in New Issue
Block a user