diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-17 18:54:56 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-17 18:54:56 -0500 |
commit | 22b4eb5e3174efb49791c62823d0cccc35394c36 (patch) | |
tree | 7324d6b53ad3c18c244094ad5d51b500716d7304 /fs/xfs/xfs_file.c | |
parent | d65773b22b749252b2805dcf96bdeb951a9481d8 (diff) | |
parent | d060646436233912178e6b9e3a7f30a41214220f (diff) |
Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
* 'for-linus' of git://oss.sgi.com/xfs/xfs:
xfs: cleanup xfs_file_aio_write
xfs: always return with the iolock held from xfs_file_aio_write_checks
xfs: remove the i_new_size field in struct xfs_inode
xfs: remove the i_size field in struct xfs_inode
xfs: replace i_pin_wait with a bit waitqueue
xfs: replace i_flock with a sleeping bitlock
xfs: make i_flags an unsigned long
xfs: remove the if_ext_max field in struct xfs_ifork
xfs: remove the unused dm_attrs structure
xfs: cleanup xfs_iomap_eof_align_last_fsb
xfs: remove xfs_itruncate_data
Diffstat (limited to 'fs/xfs/xfs_file.c')
-rw-r--r-- | fs/xfs/xfs_file.c | 184 |
1 files changed, 51 insertions, 133 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index f675f3d9d7b3..7e5bc872f2b4 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -327,7 +327,7 @@ xfs_file_aio_read( | |||
327 | mp->m_rtdev_targp : mp->m_ddev_targp; | 327 | mp->m_rtdev_targp : mp->m_ddev_targp; |
328 | if ((iocb->ki_pos & target->bt_smask) || | 328 | if ((iocb->ki_pos & target->bt_smask) || |
329 | (size & target->bt_smask)) { | 329 | (size & target->bt_smask)) { |
330 | if (iocb->ki_pos == ip->i_size) | 330 | if (iocb->ki_pos == i_size_read(inode)) |
331 | return 0; | 331 | return 0; |
332 | return -XFS_ERROR(EINVAL); | 332 | return -XFS_ERROR(EINVAL); |
333 | } | 333 | } |
@@ -412,51 +412,6 @@ xfs_file_splice_read( | |||
412 | return ret; | 412 | return ret; |
413 | } | 413 | } |
414 | 414 | ||
415 | STATIC void | ||
416 | xfs_aio_write_isize_update( | ||
417 | struct inode *inode, | ||
418 | loff_t *ppos, | ||
419 | ssize_t bytes_written) | ||
420 | { | ||
421 | struct xfs_inode *ip = XFS_I(inode); | ||
422 | xfs_fsize_t isize = i_size_read(inode); | ||
423 | |||
424 | if (bytes_written > 0) | ||
425 | XFS_STATS_ADD(xs_write_bytes, bytes_written); | ||
426 | |||
427 | if (unlikely(bytes_written < 0 && bytes_written != -EFAULT && | ||
428 | *ppos > isize)) | ||
429 | *ppos = isize; | ||
430 | |||
431 | if (*ppos > ip->i_size) { | ||
432 | xfs_rw_ilock(ip, XFS_ILOCK_EXCL); | ||
433 | if (*ppos > ip->i_size) | ||
434 | ip->i_size = *ppos; | ||
435 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); | ||
436 | } | ||
437 | } | ||
438 | |||
439 | /* | ||
440 | * If this was a direct or synchronous I/O that failed (such as ENOSPC) then | ||
441 | * part of the I/O may have been written to disk before the error occurred. In | ||
442 | * this case the on-disk file size may have been adjusted beyond the in-memory | ||
443 | * file size and now needs to be truncated back. | ||
444 | */ | ||
445 | STATIC void | ||
446 | xfs_aio_write_newsize_update( | ||
447 | struct xfs_inode *ip, | ||
448 | xfs_fsize_t new_size) | ||
449 | { | ||
450 | if (new_size == ip->i_new_size) { | ||
451 | xfs_rw_ilock(ip, XFS_ILOCK_EXCL); | ||
452 | if (new_size == ip->i_new_size) | ||
453 | ip->i_new_size = 0; | ||
454 | if (ip->i_d.di_size > ip->i_size) | ||
455 | ip->i_d.di_size = ip->i_size; | ||
456 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); | ||
457 | } | ||
458 | } | ||
459 | |||
460 | /* | 415 | /* |
461 | * xfs_file_splice_write() does not use xfs_rw_ilock() because | 416 | * xfs_file_splice_write() does not use xfs_rw_ilock() because |
462 | * generic_file_splice_write() takes the i_mutex itself. This, in theory, | 417 | * generic_file_splice_write() takes the i_mutex itself. This, in theory, |
@@ -475,7 +430,6 @@ xfs_file_splice_write( | |||
475 | { | 430 | { |
476 | struct inode *inode = outfilp->f_mapping->host; | 431 | struct inode *inode = outfilp->f_mapping->host; |
477 | struct xfs_inode *ip = XFS_I(inode); | 432 | struct xfs_inode *ip = XFS_I(inode); |
478 | xfs_fsize_t new_size; | ||
479 | int ioflags = 0; | 433 | int ioflags = 0; |
480 | ssize_t ret; | 434 | ssize_t ret; |
481 | 435 | ||
@@ -489,19 +443,12 @@ xfs_file_splice_write( | |||
489 | 443 | ||
490 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 444 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
491 | 445 | ||
492 | new_size = *ppos + count; | ||
493 | |||
494 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
495 | if (new_size > ip->i_size) | ||
496 | ip->i_new_size = new_size; | ||
497 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
498 | |||
499 | trace_xfs_file_splice_write(ip, count, *ppos, ioflags); | 446 | trace_xfs_file_splice_write(ip, count, *ppos, ioflags); |
500 | 447 | ||
501 | ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); | 448 | ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); |
449 | if (ret > 0) | ||
450 | XFS_STATS_ADD(xs_write_bytes, ret); | ||
502 | 451 | ||
503 | xfs_aio_write_isize_update(inode, ppos, ret); | ||
504 | xfs_aio_write_newsize_update(ip, new_size); | ||
505 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 452 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
506 | return ret; | 453 | return ret; |
507 | } | 454 | } |
@@ -689,28 +636,26 @@ out_lock: | |||
689 | /* | 636 | /* |
690 | * Common pre-write limit and setup checks. | 637 | * Common pre-write limit and setup checks. |
691 | * | 638 | * |
692 | * Returns with iolock held according to @iolock. | 639 | * Called with the iolocked held either shared and exclusive according to |
640 | * @iolock, and returns with it held. Might upgrade the iolock to exclusive | ||
641 | * if called for a direct write beyond i_size. | ||
693 | */ | 642 | */ |
694 | STATIC ssize_t | 643 | STATIC ssize_t |
695 | xfs_file_aio_write_checks( | 644 | xfs_file_aio_write_checks( |
696 | struct file *file, | 645 | struct file *file, |
697 | loff_t *pos, | 646 | loff_t *pos, |
698 | size_t *count, | 647 | size_t *count, |
699 | xfs_fsize_t *new_sizep, | ||
700 | int *iolock) | 648 | int *iolock) |
701 | { | 649 | { |
702 | struct inode *inode = file->f_mapping->host; | 650 | struct inode *inode = file->f_mapping->host; |
703 | struct xfs_inode *ip = XFS_I(inode); | 651 | struct xfs_inode *ip = XFS_I(inode); |
704 | xfs_fsize_t new_size; | ||
705 | int error = 0; | 652 | int error = 0; |
706 | 653 | ||
707 | xfs_rw_ilock(ip, XFS_ILOCK_EXCL); | 654 | xfs_rw_ilock(ip, XFS_ILOCK_EXCL); |
708 | *new_sizep = 0; | ||
709 | restart: | 655 | restart: |
710 | error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode)); | 656 | error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode)); |
711 | if (error) { | 657 | if (error) { |
712 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock); | 658 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); |
713 | *iolock = 0; | ||
714 | return error; | 659 | return error; |
715 | } | 660 | } |
716 | 661 | ||
@@ -720,36 +665,21 @@ restart: | |||
720 | /* | 665 | /* |
721 | * If the offset is beyond the size of the file, we need to zero any | 666 | * If the offset is beyond the size of the file, we need to zero any |
722 | * blocks that fall between the existing EOF and the start of this | 667 | * blocks that fall between the existing EOF and the start of this |
723 | * write. There is no need to issue zeroing if another in-flght IO ends | 668 | * write. If zeroing is needed and we are currently holding the |
724 | * at or before this one If zeronig is needed and we are currently | 669 | * iolock shared, we need to update it to exclusive which involves |
725 | * holding the iolock shared, we need to update it to exclusive which | 670 | * dropping all locks and relocking to maintain correct locking order. |
726 | * involves dropping all locks and relocking to maintain correct locking | 671 | * If we do this, restart the function to ensure all checks and values |
727 | * order. If we do this, restart the function to ensure all checks and | 672 | * are still valid. |
728 | * values are still valid. | ||
729 | */ | 673 | */ |
730 | if ((ip->i_new_size && *pos > ip->i_new_size) || | 674 | if (*pos > i_size_read(inode)) { |
731 | (!ip->i_new_size && *pos > ip->i_size)) { | ||
732 | if (*iolock == XFS_IOLOCK_SHARED) { | 675 | if (*iolock == XFS_IOLOCK_SHARED) { |
733 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock); | 676 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock); |
734 | *iolock = XFS_IOLOCK_EXCL; | 677 | *iolock = XFS_IOLOCK_EXCL; |
735 | xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock); | 678 | xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock); |
736 | goto restart; | 679 | goto restart; |
737 | } | 680 | } |
738 | error = -xfs_zero_eof(ip, *pos, ip->i_size); | 681 | error = -xfs_zero_eof(ip, *pos, i_size_read(inode)); |
739 | } | 682 | } |
740 | |||
741 | /* | ||
742 | * If this IO extends beyond EOF, we may need to update ip->i_new_size. | ||
743 | * We have already zeroed space beyond EOF (if necessary). Only update | ||
744 | * ip->i_new_size if this IO ends beyond any other in-flight writes. | ||
745 | */ | ||
746 | new_size = *pos + *count; | ||
747 | if (new_size > ip->i_size) { | ||
748 | if (new_size > ip->i_new_size) | ||
749 | ip->i_new_size = new_size; | ||
750 | *new_sizep = new_size; | ||
751 | } | ||
752 | |||
753 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); | 683 | xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); |
754 | if (error) | 684 | if (error) |
755 | return error; | 685 | return error; |
@@ -794,9 +724,7 @@ xfs_file_dio_aio_write( | |||
794 | const struct iovec *iovp, | 724 | const struct iovec *iovp, |
795 | unsigned long nr_segs, | 725 | unsigned long nr_segs, |
796 | loff_t pos, | 726 | loff_t pos, |
797 | size_t ocount, | 727 | size_t ocount) |
798 | xfs_fsize_t *new_size, | ||
799 | int *iolock) | ||
800 | { | 728 | { |
801 | struct file *file = iocb->ki_filp; | 729 | struct file *file = iocb->ki_filp; |
802 | struct address_space *mapping = file->f_mapping; | 730 | struct address_space *mapping = file->f_mapping; |
@@ -806,10 +734,10 @@ xfs_file_dio_aio_write( | |||
806 | ssize_t ret = 0; | 734 | ssize_t ret = 0; |
807 | size_t count = ocount; | 735 | size_t count = ocount; |
808 | int unaligned_io = 0; | 736 | int unaligned_io = 0; |
737 | int iolock; | ||
809 | struct xfs_buftarg *target = XFS_IS_REALTIME_INODE(ip) ? | 738 | struct xfs_buftarg *target = XFS_IS_REALTIME_INODE(ip) ? |
810 | mp->m_rtdev_targp : mp->m_ddev_targp; | 739 | mp->m_rtdev_targp : mp->m_ddev_targp; |
811 | 740 | ||
812 | *iolock = 0; | ||
813 | if ((pos & target->bt_smask) || (count & target->bt_smask)) | 741 | if ((pos & target->bt_smask) || (count & target->bt_smask)) |
814 | return -XFS_ERROR(EINVAL); | 742 | return -XFS_ERROR(EINVAL); |
815 | 743 | ||
@@ -824,31 +752,31 @@ xfs_file_dio_aio_write( | |||
824 | * EOF zeroing cases and fill out the new inode size as appropriate. | 752 | * EOF zeroing cases and fill out the new inode size as appropriate. |
825 | */ | 753 | */ |
826 | if (unaligned_io || mapping->nrpages) | 754 | if (unaligned_io || mapping->nrpages) |
827 | *iolock = XFS_IOLOCK_EXCL; | 755 | iolock = XFS_IOLOCK_EXCL; |
828 | else | 756 | else |
829 | *iolock = XFS_IOLOCK_SHARED; | 757 | iolock = XFS_IOLOCK_SHARED; |
830 | xfs_rw_ilock(ip, *iolock); | 758 | xfs_rw_ilock(ip, iolock); |
831 | 759 | ||
832 | /* | 760 | /* |
833 | * Recheck if there are cached pages that need invalidate after we got | 761 | * Recheck if there are cached pages that need invalidate after we got |
834 | * the iolock to protect against other threads adding new pages while | 762 | * the iolock to protect against other threads adding new pages while |
835 | * we were waiting for the iolock. | 763 | * we were waiting for the iolock. |
836 | */ | 764 | */ |
837 | if (mapping->nrpages && *iolock == XFS_IOLOCK_SHARED) { | 765 | if (mapping->nrpages && iolock == XFS_IOLOCK_SHARED) { |
838 | xfs_rw_iunlock(ip, *iolock); | 766 | xfs_rw_iunlock(ip, iolock); |
839 | *iolock = XFS_IOLOCK_EXCL; | 767 | iolock = XFS_IOLOCK_EXCL; |
840 | xfs_rw_ilock(ip, *iolock); | 768 | xfs_rw_ilock(ip, iolock); |
841 | } | 769 | } |
842 | 770 | ||
843 | ret = xfs_file_aio_write_checks(file, &pos, &count, new_size, iolock); | 771 | ret = xfs_file_aio_write_checks(file, &pos, &count, &iolock); |
844 | if (ret) | 772 | if (ret) |
845 | return ret; | 773 | goto out; |
846 | 774 | ||
847 | if (mapping->nrpages) { | 775 | if (mapping->nrpages) { |
848 | ret = -xfs_flushinval_pages(ip, (pos & PAGE_CACHE_MASK), -1, | 776 | ret = -xfs_flushinval_pages(ip, (pos & PAGE_CACHE_MASK), -1, |
849 | FI_REMAPF_LOCKED); | 777 | FI_REMAPF_LOCKED); |
850 | if (ret) | 778 | if (ret) |
851 | return ret; | 779 | goto out; |
852 | } | 780 | } |
853 | 781 | ||
854 | /* | 782 | /* |
@@ -857,15 +785,18 @@ xfs_file_dio_aio_write( | |||
857 | */ | 785 | */ |
858 | if (unaligned_io) | 786 | if (unaligned_io) |
859 | inode_dio_wait(inode); | 787 | inode_dio_wait(inode); |
860 | else if (*iolock == XFS_IOLOCK_EXCL) { | 788 | else if (iolock == XFS_IOLOCK_EXCL) { |
861 | xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL); | 789 | xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL); |
862 | *iolock = XFS_IOLOCK_SHARED; | 790 | iolock = XFS_IOLOCK_SHARED; |
863 | } | 791 | } |
864 | 792 | ||
865 | trace_xfs_file_direct_write(ip, count, iocb->ki_pos, 0); | 793 | trace_xfs_file_direct_write(ip, count, iocb->ki_pos, 0); |
866 | ret = generic_file_direct_write(iocb, iovp, | 794 | ret = generic_file_direct_write(iocb, iovp, |
867 | &nr_segs, pos, &iocb->ki_pos, count, ocount); | 795 | &nr_segs, pos, &iocb->ki_pos, count, ocount); |
868 | 796 | ||
797 | out: | ||
798 | xfs_rw_iunlock(ip, iolock); | ||
799 | |||
869 | /* No fallback to buffered IO on errors for XFS. */ | 800 | /* No fallback to buffered IO on errors for XFS. */ |
870 | ASSERT(ret < 0 || ret == count); | 801 | ASSERT(ret < 0 || ret == count); |
871 | return ret; | 802 | return ret; |
@@ -877,9 +808,7 @@ xfs_file_buffered_aio_write( | |||
877 | const struct iovec *iovp, | 808 | const struct iovec *iovp, |
878 | unsigned long nr_segs, | 809 | unsigned long nr_segs, |
879 | loff_t pos, | 810 | loff_t pos, |
880 | size_t ocount, | 811 | size_t ocount) |
881 | xfs_fsize_t *new_size, | ||
882 | int *iolock) | ||
883 | { | 812 | { |
884 | struct file *file = iocb->ki_filp; | 813 | struct file *file = iocb->ki_filp; |
885 | struct address_space *mapping = file->f_mapping; | 814 | struct address_space *mapping = file->f_mapping; |
@@ -887,14 +816,14 @@ xfs_file_buffered_aio_write( | |||
887 | struct xfs_inode *ip = XFS_I(inode); | 816 | struct xfs_inode *ip = XFS_I(inode); |
888 | ssize_t ret; | 817 | ssize_t ret; |
889 | int enospc = 0; | 818 | int enospc = 0; |
819 | int iolock = XFS_IOLOCK_EXCL; | ||
890 | size_t count = ocount; | 820 | size_t count = ocount; |
891 | 821 | ||
892 | *iolock = XFS_IOLOCK_EXCL; | 822 | xfs_rw_ilock(ip, iolock); |
893 | xfs_rw_ilock(ip, *iolock); | ||
894 | 823 | ||
895 | ret = xfs_file_aio_write_checks(file, &pos, &count, new_size, iolock); | 824 | ret = xfs_file_aio_write_checks(file, &pos, &count, &iolock); |
896 | if (ret) | 825 | if (ret) |
897 | return ret; | 826 | goto out; |
898 | 827 | ||
899 | /* We can write back this queue in page reclaim */ | 828 | /* We can write back this queue in page reclaim */ |
900 | current->backing_dev_info = mapping->backing_dev_info; | 829 | current->backing_dev_info = mapping->backing_dev_info; |
@@ -908,13 +837,15 @@ write_retry: | |||
908 | * page locks and retry *once* | 837 | * page locks and retry *once* |
909 | */ | 838 | */ |
910 | if (ret == -ENOSPC && !enospc) { | 839 | if (ret == -ENOSPC && !enospc) { |
911 | ret = -xfs_flush_pages(ip, 0, -1, 0, FI_NONE); | ||
912 | if (ret) | ||
913 | return ret; | ||
914 | enospc = 1; | 840 | enospc = 1; |
915 | goto write_retry; | 841 | ret = -xfs_flush_pages(ip, 0, -1, 0, FI_NONE); |
842 | if (!ret) | ||
843 | goto write_retry; | ||
916 | } | 844 | } |
845 | |||
917 | current->backing_dev_info = NULL; | 846 | current->backing_dev_info = NULL; |
847 | out: | ||
848 | xfs_rw_iunlock(ip, iolock); | ||
918 | return ret; | 849 | return ret; |
919 | } | 850 | } |
920 | 851 | ||
@@ -930,9 +861,7 @@ xfs_file_aio_write( | |||
930 | struct inode *inode = mapping->host; | 861 | struct inode *inode = mapping->host; |
931 | struct xfs_inode *ip = XFS_I(inode); | 862 | struct xfs_inode *ip = XFS_I(inode); |
932 | ssize_t ret; | 863 | ssize_t ret; |
933 | int iolock; | ||
934 | size_t ocount = 0; | 864 | size_t ocount = 0; |
935 | xfs_fsize_t new_size = 0; | ||
936 | 865 | ||
937 | XFS_STATS_INC(xs_write_calls); | 866 | XFS_STATS_INC(xs_write_calls); |
938 | 867 | ||
@@ -951,33 +880,22 @@ xfs_file_aio_write( | |||
951 | return -EIO; | 880 | return -EIO; |
952 | 881 | ||
953 | if (unlikely(file->f_flags & O_DIRECT)) | 882 | if (unlikely(file->f_flags & O_DIRECT)) |
954 | ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos, | 883 | ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos, ocount); |
955 | ocount, &new_size, &iolock); | ||
956 | else | 884 | else |
957 | ret = xfs_file_buffered_aio_write(iocb, iovp, nr_segs, pos, | 885 | ret = xfs_file_buffered_aio_write(iocb, iovp, nr_segs, pos, |
958 | ocount, &new_size, &iolock); | 886 | ocount); |
959 | |||
960 | xfs_aio_write_isize_update(inode, &iocb->ki_pos, ret); | ||
961 | 887 | ||
962 | if (ret <= 0) | 888 | if (ret > 0) { |
963 | goto out_unlock; | 889 | ssize_t err; |
964 | 890 | ||
965 | /* Handle various SYNC-type writes */ | 891 | XFS_STATS_ADD(xs_write_bytes, ret); |
966 | if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) { | ||
967 | loff_t end = pos + ret - 1; | ||
968 | int error; | ||
969 | 892 | ||
970 | xfs_rw_iunlock(ip, iolock); | 893 | /* Handle various SYNC-type writes */ |
971 | error = xfs_file_fsync(file, pos, end, | 894 | err = generic_write_sync(file, pos, ret); |
972 | (file->f_flags & __O_SYNC) ? 0 : 1); | 895 | if (err < 0) |
973 | xfs_rw_ilock(ip, iolock); | 896 | ret = err; |
974 | if (error) | ||
975 | ret = error; | ||
976 | } | 897 | } |
977 | 898 | ||
978 | out_unlock: | ||
979 | xfs_aio_write_newsize_update(ip, new_size); | ||
980 | xfs_rw_iunlock(ip, iolock); | ||
981 | return ret; | 899 | return ret; |
982 | } | 900 | } |
983 | 901 | ||