|
7 | 7 | #include <linux/iomap.h> |
8 | 8 | #include <linux/fiemap.h> |
9 | 9 | #include <linux/iversion.h> |
| 10 | +#include <linux/backing-dev.h> |
10 | 11 |
|
11 | 12 | #include "ext4_jbd2.h" |
12 | 13 | #include "ext4.h" |
@@ -733,45 +734,83 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, |
733 | 734 | int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, |
734 | 735 | unsigned copied, struct page *page) |
735 | 736 | { |
736 | | - int ret, no_expand; |
| 737 | + handle_t *handle = ext4_journal_current_handle(); |
| 738 | + int no_expand; |
737 | 739 | void *kaddr; |
738 | 740 | struct ext4_iloc iloc; |
| 741 | + int ret = 0, ret2; |
| 742 | + |
| 743 | + if (unlikely(copied < len) && !PageUptodate(page)) |
| 744 | + copied = 0; |
739 | 745 |
|
740 | | - if (unlikely(copied < len)) { |
741 | | - if (!PageUptodate(page)) { |
742 | | - copied = 0; |
| 746 | + if (likely(copied)) { |
| 747 | + ret = ext4_get_inode_loc(inode, &iloc); |
| 748 | + if (ret) { |
| 749 | + unlock_page(page); |
| 750 | + put_page(page); |
| 751 | + ext4_std_error(inode->i_sb, ret); |
743 | 752 | goto out; |
744 | 753 | } |
745 | | - } |
| 754 | + ext4_write_lock_xattr(inode, &no_expand); |
| 755 | + BUG_ON(!ext4_has_inline_data(inode)); |
746 | 756 |
|
747 | | - ret = ext4_get_inode_loc(inode, &iloc); |
748 | | - if (ret) { |
749 | | - ext4_std_error(inode->i_sb, ret); |
750 | | - copied = 0; |
751 | | - goto out; |
752 | | - } |
| 757 | + /* |
| 758 | + * ei->i_inline_off may have changed since |
| 759 | + * ext4_write_begin() called |
| 760 | + * ext4_try_to_write_inline_data() |
| 761 | + */ |
| 762 | + (void) ext4_find_inline_data_nolock(inode); |
753 | 763 |
|
754 | | - ext4_write_lock_xattr(inode, &no_expand); |
755 | | - BUG_ON(!ext4_has_inline_data(inode)); |
| 764 | + kaddr = kmap_atomic(page); |
| 765 | + ext4_write_inline_data(inode, &iloc, kaddr, pos, copied); |
| 766 | + kunmap_atomic(kaddr); |
| 767 | + SetPageUptodate(page); |
| 768 | + /* clear page dirty so that writepages wouldn't work for us. */ |
| 769 | + ClearPageDirty(page); |
756 | 770 |
|
757 | | - /* |
758 | | - * ei->i_inline_off may have changed since ext4_write_begin() |
759 | | - * called ext4_try_to_write_inline_data() |
760 | | - */ |
761 | | - (void) ext4_find_inline_data_nolock(inode); |
| 771 | + ext4_write_unlock_xattr(inode, &no_expand); |
| 772 | + brelse(iloc.bh); |
762 | 773 |
|
763 | | - kaddr = kmap_atomic(page); |
764 | | - ext4_write_inline_data(inode, &iloc, kaddr, pos, len); |
765 | | - kunmap_atomic(kaddr); |
766 | | - SetPageUptodate(page); |
767 | | - /* clear page dirty so that writepages wouldn't work for us. */ |
768 | | - ClearPageDirty(page); |
| 774 | + /* |
| 775 | + * It's important to update i_size while still holding page |
| 776 | + * lock: page writeout could otherwise come in and zero |
| 777 | + * beyond i_size. |
| 778 | + */ |
| 779 | + ext4_update_inode_size(inode, pos + copied); |
| 780 | + } |
| 781 | + unlock_page(page); |
| 782 | + put_page(page); |
769 | 783 |
|
770 | | - ext4_write_unlock_xattr(inode, &no_expand); |
771 | | - brelse(iloc.bh); |
772 | | - mark_inode_dirty(inode); |
| 784 | + /* |
| 785 | + * Don't mark the inode dirty under page lock. First, it unnecessarily |
| 786 | + * makes the holding time of page lock longer. Second, it forces lock |
| 787 | + * ordering of page lock and transaction start for journaling |
| 788 | + * filesystems. |
| 789 | + */ |
| 790 | + if (likely(copied)) |
| 791 | + mark_inode_dirty(inode); |
773 | 792 | out: |
774 | | - return copied; |
| 793 | + /* |
| 794 | + * If we didn't copy as much data as expected, we need to trim back |
| 795 | + * size of xattr containing inline data. |
| 796 | + */ |
| 797 | + if (pos + len > inode->i_size && ext4_can_truncate(inode)) |
| 798 | + ext4_orphan_add(handle, inode); |
| 799 | + |
| 800 | + ret2 = ext4_journal_stop(handle); |
| 801 | + if (!ret) |
| 802 | + ret = ret2; |
| 803 | + if (pos + len > inode->i_size) { |
| 804 | + ext4_truncate_failed_write(inode); |
| 805 | + /* |
| 806 | + * If truncate failed early the inode might still be |
| 807 | + * on the orphan list; we need to make sure the inode |
| 808 | + * is removed from the orphan list in that case. |
| 809 | + */ |
| 810 | + if (inode->i_nlink) |
| 811 | + ext4_orphan_del(NULL, inode); |
| 812 | + } |
| 813 | + return ret ? ret : copied; |
775 | 814 | } |
776 | 815 |
|
777 | 816 | struct buffer_head * |
@@ -953,43 +992,6 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, |
953 | 992 | return ret; |
954 | 993 | } |
955 | 994 |
|
956 | | -int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, |
957 | | - unsigned len, unsigned copied, |
958 | | - struct page *page) |
959 | | -{ |
960 | | - int ret; |
961 | | - |
962 | | - ret = ext4_write_inline_data_end(inode, pos, len, copied, page); |
963 | | - if (ret < 0) { |
964 | | - unlock_page(page); |
965 | | - put_page(page); |
966 | | - return ret; |
967 | | - } |
968 | | - copied = ret; |
969 | | - |
970 | | - /* |
971 | | - * No need to use i_size_read() here, the i_size |
972 | | - * cannot change under us because we hold i_mutex. |
973 | | - * |
974 | | - * But it's important to update i_size while still holding page lock: |
975 | | - * page writeout could otherwise come in and zero beyond i_size. |
976 | | - */ |
977 | | - if (pos+copied > inode->i_size) |
978 | | - i_size_write(inode, pos+copied); |
979 | | - unlock_page(page); |
980 | | - put_page(page); |
981 | | - |
982 | | - /* |
983 | | - * Don't mark the inode dirty under page lock. First, it unnecessarily |
984 | | - * makes the holding time of page lock longer. Second, it forces lock |
985 | | - * ordering of page lock and transaction start for journaling |
986 | | - * filesystems. |
987 | | - */ |
988 | | - mark_inode_dirty(inode); |
989 | | - |
990 | | - return copied; |
991 | | -} |
992 | | - |
993 | 995 | #ifdef INLINE_DIR_DEBUG |
994 | 996 | void ext4_show_inline_dir(struct inode *dir, struct buffer_head *bh, |
995 | 997 | void *inline_start, int inline_size) |
@@ -1917,6 +1919,24 @@ int ext4_inline_data_truncate(struct inode *inode, int *has_inline) |
1917 | 1919 | EXT4_I(inode)->i_disksize = i_size; |
1918 | 1920 |
|
1919 | 1921 | if (i_size < inline_size) { |
| 1922 | + /* |
| 1923 | + * if there's inline data to truncate and this file was |
| 1924 | + * converted to extents after that inline data was written, |
| 1925 | + * the extent status cache must be cleared to avoid leaving |
| 1926 | + * behind stale delayed allocated extent entries |
| 1927 | + */ |
| 1928 | + if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) { |
| 1929 | +retry: |
| 1930 | + err = ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS); |
| 1931 | + if (err == -ENOMEM) { |
| 1932 | + cond_resched(); |
| 1933 | + congestion_wait(BLK_RW_ASYNC, HZ/50); |
| 1934 | + goto retry; |
| 1935 | + } |
| 1936 | + if (err) |
| 1937 | + goto out_error; |
| 1938 | + } |
| 1939 | + |
1920 | 1940 | /* Clear the content in the xattr space. */ |
1921 | 1941 | if (inline_size > EXT4_MIN_INLINE_DATA_SIZE) { |
1922 | 1942 | if ((err = ext4_xattr_ibody_find(inode, &i, &is)) != 0) |
|
0 commit comments