diff options
author | Dave Chinner <dchinner@redhat.com> | 2011-01-10 18:23:42 -0500 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2011-01-10 18:23:42 -0500 |
commit | 4d8d15812fd9bc96d0da11467d23e0373feae933 (patch) | |
tree | 8f81ae552502cd13259f289cfee110a89579ea59 /fs/xfs/linux-2.6/xfs_file.c | |
parent | 637bbc75d9fda57c7bc77ce5ee37e29a77a0520d (diff) |
xfs: factor common write setup code
The buffered IO and direct IO write paths share a common set of
checks and limiting code prior to issuing the write. Factor that
into a common helper function.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Alex Elder <aelder@sgi.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_file.c')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_file.c | 123 |
1 files changed, 56 insertions, 67 deletions
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index e2bcf51d292e..5863dd8f448c 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
@@ -629,6 +629,58 @@ out_lock: | |||
629 | } | 629 | } |
630 | 630 | ||
631 | /* | 631 | /* |
632 | * Common pre-write limit and setup checks. | ||
633 | * | ||
634 | * Returns with iolock held according to @iolock. | ||
635 | */ | ||
636 | STATIC ssize_t | ||
637 | xfs_file_aio_write_checks( | ||
638 | struct file *file, | ||
639 | loff_t *pos, | ||
640 | size_t *count, | ||
641 | int *iolock) | ||
642 | { | ||
643 | struct inode *inode = file->f_mapping->host; | ||
644 | struct xfs_inode *ip = XFS_I(inode); | ||
645 | xfs_fsize_t new_size; | ||
646 | int error = 0; | ||
647 | |||
648 | error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode)); | ||
649 | if (error) { | ||
650 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock); | ||
651 | *iolock = 0; | ||
652 | return error; | ||
653 | } | ||
654 | |||
655 | new_size = *pos + *count; | ||
656 | if (new_size > ip->i_size) | ||
657 | ip->i_new_size = new_size; | ||
658 | |||
659 | if (likely(!(file->f_mode & FMODE_NOCMTIME))) | ||
660 | file_update_time(file); | ||
661 | |||
662 | /* | ||
663 | * If the offset is beyond the size of the file, we need to zero any | ||
664 | * blocks that fall between the existing EOF and the start of this | ||
665 | * write. | ||
666 | */ | ||
667 | if (*pos > ip->i_size) | ||
668 | error = -xfs_zero_eof(ip, *pos, ip->i_size); | ||
669 | |||
670 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); | ||
671 | if (error) | ||
672 | return error; | ||
673 | |||
674 | /* | ||
675 | * If we're writing the file then make sure to clear the setuid and | ||
676 | * setgid bits if the process is not being run by root. This keeps | ||
677 | * people from modifying setuid and setgid binaries. | ||
678 | */ | ||
679 | return file_remove_suid(file); | ||
680 | |||
681 | } | ||
682 | |||
683 | /* | ||
632 | * xfs_file_dio_aio_write - handle direct IO writes | 684 | * xfs_file_dio_aio_write - handle direct IO writes |
633 | * | 685 | * |
634 | * Lock the inode appropriately to prepare for and issue a direct IO write. | 686 | * Lock the inode appropriately to prepare for and issue a direct IO write. |
@@ -653,7 +705,6 @@ xfs_file_dio_aio_write( | |||
653 | struct xfs_inode *ip = XFS_I(inode); | 705 | struct xfs_inode *ip = XFS_I(inode); |
654 | struct xfs_mount *mp = ip->i_mount; | 706 | struct xfs_mount *mp = ip->i_mount; |
655 | ssize_t ret = 0; | 707 | ssize_t ret = 0; |
656 | xfs_fsize_t new_size; | ||
657 | size_t count = ocount; | 708 | size_t count = ocount; |
658 | struct xfs_buftarg *target = XFS_IS_REALTIME_INODE(ip) ? | 709 | struct xfs_buftarg *target = XFS_IS_REALTIME_INODE(ip) ? |
659 | mp->m_rtdev_targp : mp->m_ddev_targp; | 710 | mp->m_rtdev_targp : mp->m_ddev_targp; |
@@ -674,45 +725,8 @@ xfs_file_dio_aio_write( | |||
674 | *iolock = XFS_IOLOCK_SHARED; | 725 | *iolock = XFS_IOLOCK_SHARED; |
675 | xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock); | 726 | xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock); |
676 | 727 | ||
677 | ret = generic_write_checks(file, &pos, &count, | 728 | ret = xfs_file_aio_write_checks(file, &pos, &count, iolock); |
678 | S_ISBLK(inode->i_mode)); | 729 | if (ret) |
679 | if (ret) { | ||
680 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock); | ||
681 | *iolock = 0; | ||
682 | return ret; | ||
683 | } | ||
684 | |||
685 | new_size = pos + count; | ||
686 | if (new_size > ip->i_size) | ||
687 | ip->i_new_size = new_size; | ||
688 | |||
689 | if (likely(!(file->f_mode & FMODE_NOCMTIME))) | ||
690 | file_update_time(file); | ||
691 | |||
692 | /* | ||
693 | * If the offset is beyond the size of the file, we have a couple of | ||
694 | * things to do. First, if there is already space allocated we need to | ||
695 | * either create holes or zero the disk or ... | ||
696 | * | ||
697 | * If there is a page where the previous size lands, we need to zero it | ||
698 | * out up to the new size. | ||
699 | */ | ||
700 | if (pos > ip->i_size) { | ||
701 | ret = -xfs_zero_eof(ip, pos, ip->i_size); | ||
702 | if (ret) { | ||
703 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); | ||
704 | return ret; | ||
705 | } | ||
706 | } | ||
707 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); | ||
708 | |||
709 | /* | ||
710 | * If we're writing the file then make sure to clear the setuid and | ||
711 | * setgid bits if the process is not being run by root. This keeps | ||
712 | * people from modifying setuid and setgid binaries. | ||
713 | */ | ||
714 | ret = file_remove_suid(file); | ||
715 | if (unlikely(ret)) | ||
716 | return ret; | 730 | return ret; |
717 | 731 | ||
718 | if (mapping->nrpages) { | 732 | if (mapping->nrpages) { |
@@ -753,38 +767,13 @@ xfs_file_buffered_aio_write( | |||
753 | struct xfs_inode *ip = XFS_I(inode); | 767 | struct xfs_inode *ip = XFS_I(inode); |
754 | ssize_t ret; | 768 | ssize_t ret; |
755 | int enospc = 0; | 769 | int enospc = 0; |
756 | xfs_fsize_t new_size; | ||
757 | size_t count = ocount; | 770 | size_t count = ocount; |
758 | 771 | ||
759 | *iolock = XFS_IOLOCK_EXCL; | 772 | *iolock = XFS_IOLOCK_EXCL; |
760 | xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock); | 773 | xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock); |
761 | 774 | ||
762 | ret = generic_write_checks(file, &pos, &count, | 775 | ret = xfs_file_aio_write_checks(file, &pos, &count, iolock); |
763 | S_ISBLK(inode->i_mode)); | 776 | if (ret) |
764 | if (ret) { | ||
765 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock); | ||
766 | *iolock = 0; | ||
767 | return ret; | ||
768 | } | ||
769 | |||
770 | new_size = pos + count; | ||
771 | if (new_size > ip->i_size) | ||
772 | ip->i_new_size = new_size; | ||
773 | |||
774 | if (likely(!(file->f_mode & FMODE_NOCMTIME))) | ||
775 | file_update_time(file); | ||
776 | |||
777 | if (pos > ip->i_size) { | ||
778 | ret = -xfs_zero_eof(ip, pos, ip->i_size); | ||
779 | if (ret) { | ||
780 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); | ||
781 | return ret; | ||
782 | } | ||
783 | } | ||
784 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); | ||
785 | |||
786 | ret = file_remove_suid(file); | ||
787 | if (unlikely(ret)) | ||
788 | return ret; | 777 | return ret; |
789 | 778 | ||
790 | /* We can write back this queue in page reclaim */ | 779 | /* We can write back this queue in page reclaim */ |