aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorLachlan McIlroy <lachlan@sgi.com>2007-05-07 23:50:12 -0400
committerTim Shimmin <tes@sgi.com>2007-05-07 23:50:12 -0400
commit71dfd5a396d11512aa6c8ed0d35b268bc084bb9b (patch)
tree843b46b1e42df50707c160650695e074f1e8d7f6 /fs/xfs
parent3a02ee1828915d6540b415a160344775e2a4f918 (diff)
[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/xfs')
-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:
724 goto out_unlock_mutex; 724 goto out_unlock_mutex;
725 } 725 }
726 726
727 if (ioflags & IO_ISDIRECT) {
728 xfs_buftarg_t *target =
729 (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
730 mp->m_rtdev_targp : mp->m_ddev_targp;
731
732 if ((pos & target->bt_smask) || (count & target->bt_smask)) {
733 xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
734 return XFS_ERROR(-EINVAL);
735 }
736
737 if (!need_i_mutex && (VN_CACHED(vp) || pos > xip->i_size)) {
738 xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
739 iolock = XFS_IOLOCK_EXCL;
740 locktype = VRWLOCK_WRITE;
741 need_i_mutex = 1;
742 mutex_lock(&inode->i_mutex);
743 xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);
744 goto start;
745 }
746 }
747
748 new_size = pos + count;
749 if (new_size > xip->i_size)
750 io->io_new_size = new_size;
751
752 if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) && 727 if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
753 !(ioflags & IO_INVIS) && !eventsent)) { 728 !(ioflags & IO_INVIS) && !eventsent)) {
754 loff_t savedsize = pos;
755 int dmflags = FILP_DELAY_FLAG(file); 729 int dmflags = FILP_DELAY_FLAG(file);
756 730
757 if (need_i_mutex) 731 if (need_i_mutex)
@@ -774,10 +748,35 @@ start:
774 * event prevents another call to XFS_SEND_DATA, which is 748 * event prevents another call to XFS_SEND_DATA, which is
775 * what allows the size to change in the first place. 749 * what allows the size to change in the first place.
776 */ 750 */
777 if ((file->f_flags & O_APPEND) && savedsize != xip->i_size) 751 if ((file->f_flags & O_APPEND) && pos != xip->i_size)
778 goto start; 752 goto start;
779 } 753 }
780 754
755 if (ioflags & IO_ISDIRECT) {
756 xfs_buftarg_t *target =
757 (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
758 mp->m_rtdev_targp : mp->m_ddev_targp;
759
760 if ((pos & target->bt_smask) || (count & target->bt_smask)) {
761 xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
762 return XFS_ERROR(-EINVAL);
763 }
764
765 if (!need_i_mutex && (VN_CACHED(vp) || pos > xip->i_size)) {
766 xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
767 iolock = XFS_IOLOCK_EXCL;
768 locktype = VRWLOCK_WRITE;
769 need_i_mutex = 1;
770 mutex_lock(&inode->i_mutex);
771 xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);
772 goto start;
773 }
774 }
775
776 new_size = pos + count;
777 if (new_size > xip->i_size)
778 io->io_new_size = new_size;
779
781 if (likely(!(ioflags & IO_INVIS))) { 780 if (likely(!(ioflags & IO_INVIS))) {
782 file_update_time(file); 781 file_update_time(file);
783 xfs_ichgtime_fast(xip, inode, 782 xfs_ichgtime_fast(xip, inode,