diff options
Diffstat (limited to 'fs/ext4/inline.c')
-rw-r--r-- | fs/ext4/inline.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 01274b1e7d40..65f7ffb5437f 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c | |||
@@ -771,6 +771,183 @@ ext4_journalled_write_inline_data(struct inode *inode, | |||
771 | return iloc.bh; | 771 | return iloc.bh; |
772 | } | 772 | } |
773 | 773 | ||
774 | /* | ||
775 | * Try to make the page cache and handle ready for the inline data case. | ||
776 | * We can call this function in 2 cases: | ||
777 | * 1. The inode is created and the first write exceeds inline size. We can | ||
778 | * clear the inode state safely. | ||
779 | * 2. The inode has inline data, then we need to read the data, make it | ||
780 | * update and dirty so that ext4_da_writepages can handle it. We don't | ||
781 | * need to start the journal since the file's metatdata isn't changed now. | ||
782 | */ | ||
783 | static int ext4_da_convert_inline_data_to_extent(struct address_space *mapping, | ||
784 | struct inode *inode, | ||
785 | unsigned flags, | ||
786 | void **fsdata) | ||
787 | { | ||
788 | int ret = 0, inline_size; | ||
789 | struct page *page; | ||
790 | |||
791 | page = grab_cache_page_write_begin(mapping, 0, flags); | ||
792 | if (!page) | ||
793 | return -ENOMEM; | ||
794 | |||
795 | down_read(&EXT4_I(inode)->xattr_sem); | ||
796 | if (!ext4_has_inline_data(inode)) { | ||
797 | ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); | ||
798 | goto out; | ||
799 | } | ||
800 | |||
801 | inline_size = ext4_get_inline_size(inode); | ||
802 | |||
803 | if (!PageUptodate(page)) { | ||
804 | ret = ext4_read_inline_page(inode, page); | ||
805 | if (ret < 0) | ||
806 | goto out; | ||
807 | } | ||
808 | |||
809 | ret = __block_write_begin(page, 0, inline_size, | ||
810 | ext4_da_get_block_prep); | ||
811 | if (ret) { | ||
812 | ext4_truncate_failed_write(inode); | ||
813 | goto out; | ||
814 | } | ||
815 | |||
816 | SetPageDirty(page); | ||
817 | SetPageUptodate(page); | ||
818 | ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); | ||
819 | *fsdata = (void *)CONVERT_INLINE_DATA; | ||
820 | |||
821 | out: | ||
822 | up_read(&EXT4_I(inode)->xattr_sem); | ||
823 | if (page) { | ||
824 | unlock_page(page); | ||
825 | page_cache_release(page); | ||
826 | } | ||
827 | return ret; | ||
828 | } | ||
829 | |||
830 | /* | ||
831 | * Prepare the write for the inline data. | ||
832 | * If the the data can be written into the inode, we just read | ||
833 | * the page and make it uptodate, and start the journal. | ||
834 | * Otherwise read the page, makes it dirty so that it can be | ||
835 | * handle in writepages(the i_disksize update is left to the | ||
836 | * normal ext4_da_write_end). | ||
837 | */ | ||
838 | int ext4_da_write_inline_data_begin(struct address_space *mapping, | ||
839 | struct inode *inode, | ||
840 | loff_t pos, unsigned len, | ||
841 | unsigned flags, | ||
842 | struct page **pagep, | ||
843 | void **fsdata) | ||
844 | { | ||
845 | int ret, inline_size; | ||
846 | handle_t *handle; | ||
847 | struct page *page; | ||
848 | struct ext4_iloc iloc; | ||
849 | |||
850 | ret = ext4_get_inode_loc(inode, &iloc); | ||
851 | if (ret) | ||
852 | return ret; | ||
853 | |||
854 | handle = ext4_journal_start(inode, 1); | ||
855 | if (IS_ERR(handle)) { | ||
856 | ret = PTR_ERR(handle); | ||
857 | handle = NULL; | ||
858 | goto out; | ||
859 | } | ||
860 | |||
861 | inline_size = ext4_get_max_inline_size(inode); | ||
862 | |||
863 | ret = -ENOSPC; | ||
864 | if (inline_size >= pos + len) { | ||
865 | ret = ext4_prepare_inline_data(handle, inode, pos + len); | ||
866 | if (ret && ret != -ENOSPC) | ||
867 | goto out; | ||
868 | } | ||
869 | |||
870 | if (ret == -ENOSPC) { | ||
871 | ret = ext4_da_convert_inline_data_to_extent(mapping, | ||
872 | inode, | ||
873 | flags, | ||
874 | fsdata); | ||
875 | goto out; | ||
876 | } | ||
877 | |||
878 | /* | ||
879 | * We cannot recurse into the filesystem as the transaction | ||
880 | * is already started. | ||
881 | */ | ||
882 | flags |= AOP_FLAG_NOFS; | ||
883 | |||
884 | page = grab_cache_page_write_begin(mapping, 0, flags); | ||
885 | if (!page) { | ||
886 | ret = -ENOMEM; | ||
887 | goto out; | ||
888 | } | ||
889 | |||
890 | down_read(&EXT4_I(inode)->xattr_sem); | ||
891 | if (!ext4_has_inline_data(inode)) { | ||
892 | ret = 0; | ||
893 | goto out_release_page; | ||
894 | } | ||
895 | |||
896 | if (!PageUptodate(page)) { | ||
897 | ret = ext4_read_inline_page(inode, page); | ||
898 | if (ret < 0) | ||
899 | goto out_release_page; | ||
900 | } | ||
901 | |||
902 | up_read(&EXT4_I(inode)->xattr_sem); | ||
903 | *pagep = page; | ||
904 | handle = NULL; | ||
905 | brelse(iloc.bh); | ||
906 | return 1; | ||
907 | out_release_page: | ||
908 | up_read(&EXT4_I(inode)->xattr_sem); | ||
909 | unlock_page(page); | ||
910 | page_cache_release(page); | ||
911 | out: | ||
912 | if (handle) | ||
913 | ext4_journal_stop(handle); | ||
914 | brelse(iloc.bh); | ||
915 | return ret; | ||
916 | } | ||
917 | |||
918 | int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, | ||
919 | unsigned len, unsigned copied, | ||
920 | struct page *page) | ||
921 | { | ||
922 | int i_size_changed = 0; | ||
923 | |||
924 | copied = ext4_write_inline_data_end(inode, pos, len, copied, page); | ||
925 | |||
926 | /* | ||
927 | * No need to use i_size_read() here, the i_size | ||
928 | * cannot change under us because we hold i_mutex. | ||
929 | * | ||
930 | * But it's important to update i_size while still holding page lock: | ||
931 | * page writeout could otherwise come in and zero beyond i_size. | ||
932 | */ | ||
933 | if (pos+copied > inode->i_size) { | ||
934 | i_size_write(inode, pos+copied); | ||
935 | i_size_changed = 1; | ||
936 | } | ||
937 | unlock_page(page); | ||
938 | page_cache_release(page); | ||
939 | |||
940 | /* | ||
941 | * Don't mark the inode dirty under page lock. First, it unnecessarily | ||
942 | * makes the holding time of page lock longer. Second, it forces lock | ||
943 | * ordering of page lock and transaction start for journaling | ||
944 | * filesystems. | ||
945 | */ | ||
946 | if (i_size_changed) | ||
947 | mark_inode_dirty(inode); | ||
948 | |||
949 | return copied; | ||
950 | } | ||
774 | 951 | ||
775 | int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) | 952 | int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) |
776 | { | 953 | { |