summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLachlan McIlroy <lachlan@sgi.com>2007-05-08 13:50:12 +1000
committerTim Shimmin <tes@sgi.com>2007-05-08 13:50:12 +1000
commit71dfd5a396d11512aa6c8ed0d35b268bc084bb9b (patch)
tree843b46b1e42df50707c160650695e074f1e8d7f6 /fs
parent3a02ee1828915d6540b415a160344775e2a4f918 (diff)
downloadlinux-stable-71dfd5a396d11512aa6c8ed0d35b268bc084bb9b.tar.gz
linux-stable-71dfd5a396d11512aa6c8ed0d35b268bc084bb9b.tar.bz2
linux-stable-71dfd5a396d11512aa6c8ed0d35b268bc084bb9b.zip
[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>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.c53
1 files changed, 26 insertions, 27 deletions
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index 82ab792c7fc9..b2a1beb33888 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -724,34 +724,8 @@ start:
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)
@@ -774,10 +748,35 @@ start:
* 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,