diff options
author | Joseph Qi <joseph.qi@huawei.com> | 2015-02-16 19:00:00 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-16 20:56:05 -0500 |
commit | 24c40b329e03dd38a1ca2225c739db67f4441343 (patch) | |
tree | ac44a8faee0103987e75fd01885042745d645421 /fs/ocfs2 | |
parent | ed460cffc26ba4ec663a89589d81290ca92c5010 (diff) |
ocfs2: implement ocfs2_direct_IO_write
Implement ocfs2_direct_IO_write. Add the inode to orphan dir first, and
then delete it once append O_DIRECT finished.
This is to make sure block allocation and inode size are consistent.
[akpm@linux-foundation.org: fix it for "block: Add discard flag to blkdev_issue_zeroout() function"]
Signed-off-by: Joseph Qi <joseph.qi@huawei.com>
Cc: Weiwei Wang <wangww631@huawei.com>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Xuejiufei <xuejiufei@huawei.com>
Cc: alex chen <alex.chen@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r-- | fs/ocfs2/aops.c | 197 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2.h | 10 |
2 files changed, 204 insertions, 3 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 46d93e941f3d..be5986b7e5c6 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/pipe_fs_i.h> | 28 | #include <linux/pipe_fs_i.h> |
29 | #include <linux/mpage.h> | 29 | #include <linux/mpage.h> |
30 | #include <linux/quotaops.h> | 30 | #include <linux/quotaops.h> |
31 | #include <linux/blkdev.h> | ||
31 | 32 | ||
32 | #include <cluster/masklog.h> | 33 | #include <cluster/masklog.h> |
33 | 34 | ||
@@ -47,6 +48,9 @@ | |||
47 | #include "ocfs2_trace.h" | 48 | #include "ocfs2_trace.h" |
48 | 49 | ||
49 | #include "buffer_head_io.h" | 50 | #include "buffer_head_io.h" |
51 | #include "dir.h" | ||
52 | #include "namei.h" | ||
53 | #include "sysfile.h" | ||
50 | 54 | ||
51 | static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock, | 55 | static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock, |
52 | struct buffer_head *bh_result, int create) | 56 | struct buffer_head *bh_result, int create) |
@@ -597,6 +601,184 @@ static int ocfs2_releasepage(struct page *page, gfp_t wait) | |||
597 | return try_to_free_buffers(page); | 601 | return try_to_free_buffers(page); |
598 | } | 602 | } |
599 | 603 | ||
604 | static int ocfs2_is_overwrite(struct ocfs2_super *osb, | ||
605 | struct inode *inode, loff_t offset) | ||
606 | { | ||
607 | int ret = 0; | ||
608 | u32 v_cpos = 0; | ||
609 | u32 p_cpos = 0; | ||
610 | unsigned int num_clusters = 0; | ||
611 | unsigned int ext_flags = 0; | ||
612 | |||
613 | v_cpos = ocfs2_bytes_to_clusters(osb->sb, offset); | ||
614 | ret = ocfs2_get_clusters(inode, v_cpos, &p_cpos, | ||
615 | &num_clusters, &ext_flags); | ||
616 | if (ret < 0) { | ||
617 | mlog_errno(ret); | ||
618 | return ret; | ||
619 | } | ||
620 | |||
621 | if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN)) | ||
622 | return 1; | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, | ||
628 | struct iov_iter *iter, | ||
629 | loff_t offset) | ||
630 | { | ||
631 | ssize_t ret = 0; | ||
632 | ssize_t written = 0; | ||
633 | bool orphaned = false; | ||
634 | int is_overwrite = 0; | ||
635 | struct file *file = iocb->ki_filp; | ||
636 | struct inode *inode = file_inode(file)->i_mapping->host; | ||
637 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
638 | struct buffer_head *di_bh = NULL; | ||
639 | size_t count = iter->count; | ||
640 | journal_t *journal = osb->journal->j_journal; | ||
641 | u32 zero_len; | ||
642 | int cluster_align; | ||
643 | loff_t final_size = offset + count; | ||
644 | int append_write = offset >= i_size_read(inode) ? 1 : 0; | ||
645 | unsigned int num_clusters = 0; | ||
646 | unsigned int ext_flags = 0; | ||
647 | |||
648 | { | ||
649 | u64 o = offset; | ||
650 | |||
651 | zero_len = do_div(o, 1 << osb->s_clustersize_bits); | ||
652 | cluster_align = !zero_len; | ||
653 | } | ||
654 | |||
655 | /* | ||
656 | * when final_size > inode->i_size, inode->i_size will be | ||
657 | * updated after direct write, so add the inode to orphan | ||
658 | * dir first. | ||
659 | */ | ||
660 | if (final_size > i_size_read(inode)) { | ||
661 | ret = ocfs2_add_inode_to_orphan(osb, inode); | ||
662 | if (ret < 0) { | ||
663 | mlog_errno(ret); | ||
664 | goto out; | ||
665 | } | ||
666 | orphaned = true; | ||
667 | } | ||
668 | |||
669 | if (append_write) { | ||
670 | ret = ocfs2_inode_lock(inode, &di_bh, 1); | ||
671 | if (ret < 0) { | ||
672 | mlog_errno(ret); | ||
673 | goto clean_orphan; | ||
674 | } | ||
675 | |||
676 | if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) | ||
677 | ret = ocfs2_zero_extend(inode, di_bh, offset); | ||
678 | else | ||
679 | ret = ocfs2_extend_no_holes(inode, di_bh, offset, | ||
680 | offset); | ||
681 | if (ret < 0) { | ||
682 | mlog_errno(ret); | ||
683 | ocfs2_inode_unlock(inode, 1); | ||
684 | brelse(di_bh); | ||
685 | goto clean_orphan; | ||
686 | } | ||
687 | |||
688 | is_overwrite = ocfs2_is_overwrite(osb, inode, offset); | ||
689 | if (is_overwrite < 0) { | ||
690 | mlog_errno(is_overwrite); | ||
691 | ocfs2_inode_unlock(inode, 1); | ||
692 | brelse(di_bh); | ||
693 | goto clean_orphan; | ||
694 | } | ||
695 | |||
696 | ocfs2_inode_unlock(inode, 1); | ||
697 | brelse(di_bh); | ||
698 | di_bh = NULL; | ||
699 | } | ||
700 | |||
701 | written = __blockdev_direct_IO(WRITE, iocb, inode, inode->i_sb->s_bdev, | ||
702 | iter, offset, | ||
703 | ocfs2_direct_IO_get_blocks, | ||
704 | ocfs2_dio_end_io, NULL, 0); | ||
705 | if (unlikely(written < 0)) { | ||
706 | loff_t i_size = i_size_read(inode); | ||
707 | |||
708 | if (offset + count > i_size) { | ||
709 | ret = ocfs2_inode_lock(inode, &di_bh, 1); | ||
710 | if (ret < 0) { | ||
711 | mlog_errno(ret); | ||
712 | goto clean_orphan; | ||
713 | } | ||
714 | |||
715 | if (i_size == i_size_read(inode)) { | ||
716 | ret = ocfs2_truncate_file(inode, di_bh, | ||
717 | i_size); | ||
718 | if (ret < 0) { | ||
719 | if (ret != -ENOSPC) | ||
720 | mlog_errno(ret); | ||
721 | |||
722 | ocfs2_inode_unlock(inode, 1); | ||
723 | brelse(di_bh); | ||
724 | goto clean_orphan; | ||
725 | } | ||
726 | } | ||
727 | |||
728 | ocfs2_inode_unlock(inode, 1); | ||
729 | brelse(di_bh); | ||
730 | |||
731 | ret = jbd2_journal_force_commit(journal); | ||
732 | if (ret < 0) | ||
733 | mlog_errno(ret); | ||
734 | } | ||
735 | } else if (written < 0 && append_write && !is_overwrite && | ||
736 | !cluster_align) { | ||
737 | u32 p_cpos = 0; | ||
738 | u32 v_cpos = ocfs2_bytes_to_clusters(osb->sb, offset); | ||
739 | |||
740 | ret = ocfs2_get_clusters(inode, v_cpos, &p_cpos, | ||
741 | &num_clusters, &ext_flags); | ||
742 | if (ret < 0) { | ||
743 | mlog_errno(ret); | ||
744 | goto clean_orphan; | ||
745 | } | ||
746 | |||
747 | BUG_ON(!p_cpos || (ext_flags & OCFS2_EXT_UNWRITTEN)); | ||
748 | |||
749 | ret = blkdev_issue_zeroout(osb->sb->s_bdev, | ||
750 | p_cpos << (osb->s_clustersize_bits - 9), | ||
751 | zero_len >> 9, GFP_KERNEL, false); | ||
752 | if (ret < 0) | ||
753 | mlog_errno(ret); | ||
754 | } | ||
755 | |||
756 | clean_orphan: | ||
757 | if (orphaned) { | ||
758 | int tmp_ret; | ||
759 | int update_isize = written > 0 ? 1 : 0; | ||
760 | loff_t end = update_isize ? offset + written : 0; | ||
761 | |||
762 | tmp_ret = ocfs2_del_inode_from_orphan(osb, inode, | ||
763 | update_isize, end); | ||
764 | if (tmp_ret < 0) { | ||
765 | ret = tmp_ret; | ||
766 | goto out; | ||
767 | } | ||
768 | |||
769 | tmp_ret = jbd2_journal_force_commit(journal); | ||
770 | if (tmp_ret < 0) { | ||
771 | ret = tmp_ret; | ||
772 | mlog_errno(tmp_ret); | ||
773 | } | ||
774 | } | ||
775 | |||
776 | out: | ||
777 | if (ret >= 0) | ||
778 | ret = written; | ||
779 | return ret; | ||
780 | } | ||
781 | |||
600 | static ssize_t ocfs2_direct_IO(int rw, | 782 | static ssize_t ocfs2_direct_IO(int rw, |
601 | struct kiocb *iocb, | 783 | struct kiocb *iocb, |
602 | struct iov_iter *iter, | 784 | struct iov_iter *iter, |
@@ -604,6 +786,9 @@ static ssize_t ocfs2_direct_IO(int rw, | |||
604 | { | 786 | { |
605 | struct file *file = iocb->ki_filp; | 787 | struct file *file = iocb->ki_filp; |
606 | struct inode *inode = file_inode(file)->i_mapping->host; | 788 | struct inode *inode = file_inode(file)->i_mapping->host; |
789 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
790 | int full_coherency = !(osb->s_mount_opt & | ||
791 | OCFS2_MOUNT_COHERENCY_BUFFERED); | ||
607 | 792 | ||
608 | /* | 793 | /* |
609 | * Fallback to buffered I/O if we see an inode without | 794 | * Fallback to buffered I/O if we see an inode without |
@@ -612,14 +797,20 @@ static ssize_t ocfs2_direct_IO(int rw, | |||
612 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) | 797 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) |
613 | return 0; | 798 | return 0; |
614 | 799 | ||
615 | /* Fallback to buffered I/O if we are appending. */ | 800 | /* Fallback to buffered I/O if we are appending and |
616 | if (i_size_read(inode) <= offset) | 801 | * concurrent O_DIRECT writes are allowed. |
802 | */ | ||
803 | if (i_size_read(inode) <= offset && !full_coherency) | ||
617 | return 0; | 804 | return 0; |
618 | 805 | ||
619 | return __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, | 806 | if (rw == READ) |
807 | return __blockdev_direct_IO(rw, iocb, inode, | ||
808 | inode->i_sb->s_bdev, | ||
620 | iter, offset, | 809 | iter, offset, |
621 | ocfs2_direct_IO_get_blocks, | 810 | ocfs2_direct_IO_get_blocks, |
622 | ocfs2_dio_end_io, NULL, 0); | 811 | ocfs2_dio_end_io, NULL, 0); |
812 | else | ||
813 | return ocfs2_direct_IO_write(iocb, iter, offset); | ||
623 | } | 814 | } |
624 | 815 | ||
625 | static void ocfs2_figure_cluster_boundaries(struct ocfs2_super *osb, | 816 | static void ocfs2_figure_cluster_boundaries(struct ocfs2_super *osb, |
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index df9a95cbea3a..7e39cd654834 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
@@ -731,6 +731,16 @@ static inline unsigned int ocfs2_clusters_for_bytes(struct super_block *sb, | |||
731 | return clusters; | 731 | return clusters; |
732 | } | 732 | } |
733 | 733 | ||
734 | static inline unsigned int ocfs2_bytes_to_clusters(struct super_block *sb, | ||
735 | u64 bytes) | ||
736 | { | ||
737 | int cl_bits = OCFS2_SB(sb)->s_clustersize_bits; | ||
738 | unsigned int clusters; | ||
739 | |||
740 | clusters = (unsigned int)(bytes >> cl_bits); | ||
741 | return clusters; | ||
742 | } | ||
743 | |||
734 | static inline u64 ocfs2_blocks_for_bytes(struct super_block *sb, | 744 | static inline u64 ocfs2_blocks_for_bytes(struct super_block *sb, |
735 | u64 bytes) | 745 | u64 bytes) |
736 | { | 746 | { |