aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/inline.c
diff options
context:
space:
mode:
authorTao Ma <boyu.mt@taobao.com>2012-12-10 14:05:57 -0500
committerTheodore Ts'o <tytso@mit.edu>2012-12-10 14:05:57 -0500
commit9c3569b50f12e47cc5e907b5e37e4a45c0c10b43 (patch)
treedfd2c1cf5ad98ca059ff2f1f330f34faed2f79eb /fs/ext4/inline.c
parent3fdcfb668fd78ec92d9bc2daddf1d41e2a8a30bb (diff)
ext4: add delalloc support for inline data
For delayed allocation mode, we write to inline data if the file is small enough. And in case of we write to some offset larger than the inline size, the 1st page is dirtied, so that ext4_da_writepages can handle the conversion. When the 1st page is initialized with blocks, the inline part is removed. Signed-off-by: Tao Ma <boyu.mt@taobao.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/inline.c')
-rw-r--r--fs/ext4/inline.c177
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 */
783static 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
821out:
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 */
838int 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;
907out_release_page:
908 up_read(&EXT4_I(inode)->xattr_sem);
909 unlock_page(page);
910 page_cache_release(page);
911out:
912 if (handle)
913 ext4_journal_stop(handle);
914 brelse(iloc.bh);
915 return ret;
916}
917
918int 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
775int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) 952int ext4_destroy_inline_data(handle_t *handle, struct inode *inode)
776{ 953{