diff options
Diffstat (limited to 'fs/ocfs2/aops.c')
-rw-r--r-- | fs/ocfs2/aops.c | 155 |
1 files changed, 141 insertions, 14 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index e1bf18c5d25e..8d2bc840c288 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -664,6 +664,117 @@ static int ocfs2_is_overwrite(struct ocfs2_super *osb, | |||
664 | return 0; | 664 | return 0; |
665 | } | 665 | } |
666 | 666 | ||
667 | static int ocfs2_direct_IO_zero_extend(struct ocfs2_super *osb, | ||
668 | struct inode *inode, loff_t offset, | ||
669 | u64 zero_len, int cluster_align) | ||
670 | { | ||
671 | u32 p_cpos = 0; | ||
672 | u32 v_cpos = ocfs2_bytes_to_clusters(osb->sb, i_size_read(inode)); | ||
673 | unsigned int num_clusters = 0; | ||
674 | unsigned int ext_flags = 0; | ||
675 | int ret = 0; | ||
676 | |||
677 | if (offset <= i_size_read(inode) || cluster_align) | ||
678 | return 0; | ||
679 | |||
680 | ret = ocfs2_get_clusters(inode, v_cpos, &p_cpos, &num_clusters, | ||
681 | &ext_flags); | ||
682 | if (ret < 0) { | ||
683 | mlog_errno(ret); | ||
684 | return ret; | ||
685 | } | ||
686 | |||
687 | if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN)) { | ||
688 | u64 s = i_size_read(inode); | ||
689 | sector_t sector = (p_cpos << (osb->s_clustersize_bits - 9)) + | ||
690 | (do_div(s, osb->s_clustersize) >> 9); | ||
691 | |||
692 | ret = blkdev_issue_zeroout(osb->sb->s_bdev, sector, | ||
693 | zero_len >> 9, GFP_NOFS, false); | ||
694 | if (ret < 0) | ||
695 | mlog_errno(ret); | ||
696 | } | ||
697 | |||
698 | return ret; | ||
699 | } | ||
700 | |||
701 | static int ocfs2_direct_IO_extend_no_holes(struct ocfs2_super *osb, | ||
702 | struct inode *inode, loff_t offset) | ||
703 | { | ||
704 | u64 zero_start, zero_len, total_zero_len; | ||
705 | u32 p_cpos = 0, clusters_to_add; | ||
706 | u32 v_cpos = ocfs2_bytes_to_clusters(osb->sb, i_size_read(inode)); | ||
707 | unsigned int num_clusters = 0; | ||
708 | unsigned int ext_flags = 0; | ||
709 | u32 size_div, offset_div; | ||
710 | int ret = 0; | ||
711 | |||
712 | { | ||
713 | u64 o = offset; | ||
714 | u64 s = i_size_read(inode); | ||
715 | |||
716 | offset_div = do_div(o, osb->s_clustersize); | ||
717 | size_div = do_div(s, osb->s_clustersize); | ||
718 | } | ||
719 | |||
720 | if (offset <= i_size_read(inode)) | ||
721 | return 0; | ||
722 | |||
723 | clusters_to_add = ocfs2_bytes_to_clusters(inode->i_sb, offset) - | ||
724 | ocfs2_bytes_to_clusters(inode->i_sb, i_size_read(inode)); | ||
725 | total_zero_len = offset - i_size_read(inode); | ||
726 | if (clusters_to_add) | ||
727 | total_zero_len -= offset_div; | ||
728 | |||
729 | /* Allocate clusters to fill out holes, and this is only needed | ||
730 | * when we add more than one clusters. Otherwise the cluster will | ||
731 | * be allocated during direct IO */ | ||
732 | if (clusters_to_add > 1) { | ||
733 | ret = ocfs2_extend_allocation(inode, | ||
734 | OCFS2_I(inode)->ip_clusters, | ||
735 | clusters_to_add - 1, 0); | ||
736 | if (ret) { | ||
737 | mlog_errno(ret); | ||
738 | goto out; | ||
739 | } | ||
740 | } | ||
741 | |||
742 | while (total_zero_len) { | ||
743 | ret = ocfs2_get_clusters(inode, v_cpos, &p_cpos, &num_clusters, | ||
744 | &ext_flags); | ||
745 | if (ret < 0) { | ||
746 | mlog_errno(ret); | ||
747 | goto out; | ||
748 | } | ||
749 | |||
750 | zero_start = ocfs2_clusters_to_bytes(osb->sb, p_cpos) + | ||
751 | size_div; | ||
752 | zero_len = ocfs2_clusters_to_bytes(osb->sb, num_clusters) - | ||
753 | size_div; | ||
754 | zero_len = min(total_zero_len, zero_len); | ||
755 | |||
756 | if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN)) { | ||
757 | ret = blkdev_issue_zeroout(osb->sb->s_bdev, | ||
758 | zero_start >> 9, zero_len >> 9, | ||
759 | GFP_NOFS, false); | ||
760 | if (ret < 0) { | ||
761 | mlog_errno(ret); | ||
762 | goto out; | ||
763 | } | ||
764 | } | ||
765 | |||
766 | total_zero_len -= zero_len; | ||
767 | v_cpos += ocfs2_bytes_to_clusters(osb->sb, zero_len + size_div); | ||
768 | |||
769 | /* Only at first iteration can be cluster not aligned. | ||
770 | * So set size_div to 0 for the rest */ | ||
771 | size_div = 0; | ||
772 | } | ||
773 | |||
774 | out: | ||
775 | return ret; | ||
776 | } | ||
777 | |||
667 | static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, | 778 | static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, |
668 | struct iov_iter *iter, | 779 | struct iov_iter *iter, |
669 | loff_t offset) | 780 | loff_t offset) |
@@ -678,8 +789,8 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, | |||
678 | struct buffer_head *di_bh = NULL; | 789 | struct buffer_head *di_bh = NULL; |
679 | size_t count = iter->count; | 790 | size_t count = iter->count; |
680 | journal_t *journal = osb->journal->j_journal; | 791 | journal_t *journal = osb->journal->j_journal; |
681 | u32 zero_len; | 792 | u64 zero_len_head, zero_len_tail; |
682 | int cluster_align; | 793 | int cluster_align_head, cluster_align_tail; |
683 | loff_t final_size = offset + count; | 794 | loff_t final_size = offset + count; |
684 | int append_write = offset >= i_size_read(inode) ? 1 : 0; | 795 | int append_write = offset >= i_size_read(inode) ? 1 : 0; |
685 | unsigned int num_clusters = 0; | 796 | unsigned int num_clusters = 0; |
@@ -687,9 +798,16 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, | |||
687 | 798 | ||
688 | { | 799 | { |
689 | u64 o = offset; | 800 | u64 o = offset; |
801 | u64 s = i_size_read(inode); | ||
802 | |||
803 | zero_len_head = do_div(o, 1 << osb->s_clustersize_bits); | ||
804 | cluster_align_head = !zero_len_head; | ||
690 | 805 | ||
691 | zero_len = do_div(o, 1 << osb->s_clustersize_bits); | 806 | zero_len_tail = osb->s_clustersize - |
692 | cluster_align = !zero_len; | 807 | do_div(s, osb->s_clustersize); |
808 | if ((offset - i_size_read(inode)) < zero_len_tail) | ||
809 | zero_len_tail = offset - i_size_read(inode); | ||
810 | cluster_align_tail = !zero_len_tail; | ||
693 | } | 811 | } |
694 | 812 | ||
695 | /* | 813 | /* |
@@ -707,21 +825,23 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, | |||
707 | } | 825 | } |
708 | 826 | ||
709 | if (append_write) { | 827 | if (append_write) { |
710 | ret = ocfs2_inode_lock(inode, &di_bh, 1); | 828 | ret = ocfs2_inode_lock(inode, NULL, 1); |
711 | if (ret < 0) { | 829 | if (ret < 0) { |
712 | mlog_errno(ret); | 830 | mlog_errno(ret); |
713 | goto clean_orphan; | 831 | goto clean_orphan; |
714 | } | 832 | } |
715 | 833 | ||
834 | /* zeroing out the previously allocated cluster tail | ||
835 | * that but not zeroed */ | ||
716 | if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) | 836 | if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) |
717 | ret = ocfs2_zero_extend(inode, di_bh, offset); | 837 | ret = ocfs2_direct_IO_zero_extend(osb, inode, offset, |
838 | zero_len_tail, cluster_align_tail); | ||
718 | else | 839 | else |
719 | ret = ocfs2_extend_no_holes(inode, di_bh, offset, | 840 | ret = ocfs2_direct_IO_extend_no_holes(osb, inode, |
720 | offset); | 841 | offset); |
721 | if (ret < 0) { | 842 | if (ret < 0) { |
722 | mlog_errno(ret); | 843 | mlog_errno(ret); |
723 | ocfs2_inode_unlock(inode, 1); | 844 | ocfs2_inode_unlock(inode, 1); |
724 | brelse(di_bh); | ||
725 | goto clean_orphan; | 845 | goto clean_orphan; |
726 | } | 846 | } |
727 | 847 | ||
@@ -729,13 +849,10 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, | |||
729 | if (is_overwrite < 0) { | 849 | if (is_overwrite < 0) { |
730 | mlog_errno(is_overwrite); | 850 | mlog_errno(is_overwrite); |
731 | ocfs2_inode_unlock(inode, 1); | 851 | ocfs2_inode_unlock(inode, 1); |
732 | brelse(di_bh); | ||
733 | goto clean_orphan; | 852 | goto clean_orphan; |
734 | } | 853 | } |
735 | 854 | ||
736 | ocfs2_inode_unlock(inode, 1); | 855 | ocfs2_inode_unlock(inode, 1); |
737 | brelse(di_bh); | ||
738 | di_bh = NULL; | ||
739 | } | 856 | } |
740 | 857 | ||
741 | written = __blockdev_direct_IO(WRITE, iocb, inode, inode->i_sb->s_bdev, | 858 | written = __blockdev_direct_IO(WRITE, iocb, inode, inode->i_sb->s_bdev, |
@@ -772,15 +889,23 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, | |||
772 | if (ret < 0) | 889 | if (ret < 0) |
773 | mlog_errno(ret); | 890 | mlog_errno(ret); |
774 | } | 891 | } |
775 | } else if (written < 0 && append_write && !is_overwrite && | 892 | } else if (written > 0 && append_write && !is_overwrite && |
776 | !cluster_align) { | 893 | !cluster_align_head) { |
894 | /* zeroing out the allocated cluster head */ | ||
777 | u32 p_cpos = 0; | 895 | u32 p_cpos = 0; |
778 | u32 v_cpos = ocfs2_bytes_to_clusters(osb->sb, offset); | 896 | u32 v_cpos = ocfs2_bytes_to_clusters(osb->sb, offset); |
779 | 897 | ||
898 | ret = ocfs2_inode_lock(inode, NULL, 0); | ||
899 | if (ret < 0) { | ||
900 | mlog_errno(ret); | ||
901 | goto clean_orphan; | ||
902 | } | ||
903 | |||
780 | ret = ocfs2_get_clusters(inode, v_cpos, &p_cpos, | 904 | ret = ocfs2_get_clusters(inode, v_cpos, &p_cpos, |
781 | &num_clusters, &ext_flags); | 905 | &num_clusters, &ext_flags); |
782 | if (ret < 0) { | 906 | if (ret < 0) { |
783 | mlog_errno(ret); | 907 | mlog_errno(ret); |
908 | ocfs2_inode_unlock(inode, 0); | ||
784 | goto clean_orphan; | 909 | goto clean_orphan; |
785 | } | 910 | } |
786 | 911 | ||
@@ -788,9 +913,11 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, | |||
788 | 913 | ||
789 | ret = blkdev_issue_zeroout(osb->sb->s_bdev, | 914 | ret = blkdev_issue_zeroout(osb->sb->s_bdev, |
790 | p_cpos << (osb->s_clustersize_bits - 9), | 915 | p_cpos << (osb->s_clustersize_bits - 9), |
791 | zero_len >> 9, GFP_KERNEL, false); | 916 | zero_len_head >> 9, GFP_NOFS, false); |
792 | if (ret < 0) | 917 | if (ret < 0) |
793 | mlog_errno(ret); | 918 | mlog_errno(ret); |
919 | |||
920 | ocfs2_inode_unlock(inode, 0); | ||
794 | } | 921 | } |
795 | 922 | ||
796 | clean_orphan: | 923 | clean_orphan: |