diff options
author | Lachlan McIlroy <lachlan@sgi.com> | 2007-05-07 23:50:12 -0400 |
---|---|---|
committer | Tim Shimmin <tes@sgi.com> | 2007-05-07 23:50:12 -0400 |
commit | 71dfd5a396d11512aa6c8ed0d35b268bc084bb9b (patch) | |
tree | 843b46b1e42df50707c160650695e074f1e8d7f6 /fs/xfs/linux-2.6 | |
parent | 3a02ee1828915d6540b415a160344775e2a4f918 (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/linux-2.6')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_lrw.c | 53 |
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, |