|
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