Commit 3fdcfb668fd78ec92d9bc2daddf1d41e2a8a30bb
Committed by
Theodore Ts'o
1 parent
f19d5870cb
Exists in
master
and in
20 other branches
ext4: add journalled write support for inline data
Signed-off-by: Tao Ma <boyu.mt@taobao.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Showing 3 changed files with 85 additions and 20 deletions Side-by-side Diff
fs/ext4/inline.c
... | ... | @@ -747,6 +747,30 @@ |
747 | 747 | return copied; |
748 | 748 | } |
749 | 749 | |
750 | +struct buffer_head * | |
751 | +ext4_journalled_write_inline_data(struct inode *inode, | |
752 | + unsigned len, | |
753 | + struct page *page) | |
754 | +{ | |
755 | + int ret; | |
756 | + void *kaddr; | |
757 | + struct ext4_iloc iloc; | |
758 | + | |
759 | + ret = ext4_get_inode_loc(inode, &iloc); | |
760 | + if (ret) { | |
761 | + ext4_std_error(inode->i_sb, ret); | |
762 | + return NULL; | |
763 | + } | |
764 | + | |
765 | + down_write(&EXT4_I(inode)->xattr_sem); | |
766 | + kaddr = kmap_atomic(page); | |
767 | + ext4_write_inline_data(inode, &iloc, kaddr, 0, len); | |
768 | + kunmap_atomic(kaddr); | |
769 | + up_write(&EXT4_I(inode)->xattr_sem); | |
770 | + | |
771 | + return iloc.bh; | |
772 | +} | |
773 | + | |
750 | 774 | |
751 | 775 | int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) |
752 | 776 | { |
fs/ext4/inode.c
... | ... | @@ -1124,16 +1124,21 @@ |
1124 | 1124 | |
1125 | 1125 | BUG_ON(!ext4_handle_valid(handle)); |
1126 | 1126 | |
1127 | - if (copied < len) { | |
1128 | - if (!PageUptodate(page)) | |
1129 | - copied = 0; | |
1130 | - page_zero_new_buffers(page, from+copied, to); | |
1131 | - } | |
1127 | + if (ext4_has_inline_data(inode)) | |
1128 | + copied = ext4_write_inline_data_end(inode, pos, len, | |
1129 | + copied, page); | |
1130 | + else { | |
1131 | + if (copied < len) { | |
1132 | + if (!PageUptodate(page)) | |
1133 | + copied = 0; | |
1134 | + page_zero_new_buffers(page, from+copied, to); | |
1135 | + } | |
1132 | 1136 | |
1133 | - ret = ext4_walk_page_buffers(handle, page_buffers(page), from, | |
1134 | - to, &partial, write_end_fn); | |
1135 | - if (!partial) | |
1136 | - SetPageUptodate(page); | |
1137 | + ret = ext4_walk_page_buffers(handle, page_buffers(page), from, | |
1138 | + to, &partial, write_end_fn); | |
1139 | + if (!partial) | |
1140 | + SetPageUptodate(page); | |
1141 | + } | |
1137 | 1142 | new_i_size = pos + copied; |
1138 | 1143 | if (new_i_size > inode->i_size) |
1139 | 1144 | i_size_write(inode, pos+copied); |
1140 | 1145 | |
1141 | 1146 | |
... | ... | @@ -1911,15 +1916,29 @@ |
1911 | 1916 | { |
1912 | 1917 | struct address_space *mapping = page->mapping; |
1913 | 1918 | struct inode *inode = mapping->host; |
1914 | - struct buffer_head *page_bufs; | |
1919 | + struct buffer_head *page_bufs = NULL; | |
1915 | 1920 | handle_t *handle = NULL; |
1916 | - int ret = 0; | |
1917 | - int err; | |
1921 | + int ret = 0, err = 0; | |
1922 | + int inline_data = ext4_has_inline_data(inode); | |
1923 | + struct buffer_head *inode_bh = NULL; | |
1918 | 1924 | |
1919 | 1925 | ClearPageChecked(page); |
1920 | - page_bufs = page_buffers(page); | |
1921 | - BUG_ON(!page_bufs); | |
1922 | - ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, bget_one); | |
1926 | + | |
1927 | + if (inline_data) { | |
1928 | + BUG_ON(page->index != 0); | |
1929 | + BUG_ON(len > ext4_get_max_inline_size(inode)); | |
1930 | + inode_bh = ext4_journalled_write_inline_data(inode, len, page); | |
1931 | + if (inode_bh == NULL) | |
1932 | + goto out; | |
1933 | + } else { | |
1934 | + page_bufs = page_buffers(page); | |
1935 | + if (!page_bufs) { | |
1936 | + BUG(); | |
1937 | + goto out; | |
1938 | + } | |
1939 | + ext4_walk_page_buffers(handle, page_bufs, 0, len, | |
1940 | + NULL, bget_one); | |
1941 | + } | |
1923 | 1942 | /* As soon as we unlock the page, it can go away, but we have |
1924 | 1943 | * references to buffers so we are safe */ |
1925 | 1944 | unlock_page(page); |
1926 | 1945 | |
... | ... | @@ -1932,11 +1951,18 @@ |
1932 | 1951 | |
1933 | 1952 | BUG_ON(!ext4_handle_valid(handle)); |
1934 | 1953 | |
1935 | - ret = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, | |
1936 | - do_journal_get_write_access); | |
1954 | + if (inline_data) { | |
1955 | + ret = ext4_journal_get_write_access(handle, inode_bh); | |
1937 | 1956 | |
1938 | - err = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, | |
1939 | - write_end_fn); | |
1957 | + err = ext4_handle_dirty_metadata(handle, inode, inode_bh); | |
1958 | + | |
1959 | + } else { | |
1960 | + ret = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, | |
1961 | + do_journal_get_write_access); | |
1962 | + | |
1963 | + err = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, | |
1964 | + write_end_fn); | |
1965 | + } | |
1940 | 1966 | if (ret == 0) |
1941 | 1967 | ret = err; |
1942 | 1968 | EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid; |
1943 | 1969 | |
... | ... | @@ -1944,9 +1970,12 @@ |
1944 | 1970 | if (!ret) |
1945 | 1971 | ret = err; |
1946 | 1972 | |
1947 | - ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, bput_one); | |
1973 | + if (!ext4_has_inline_data(inode)) | |
1974 | + ext4_walk_page_buffers(handle, page_bufs, 0, len, | |
1975 | + NULL, bput_one); | |
1948 | 1976 | ext4_set_inode_state(inode, EXT4_STATE_JDATA); |
1949 | 1977 | out: |
1978 | + brelse(inode_bh); | |
1950 | 1979 | return ret; |
1951 | 1980 | } |
1952 | 1981 |
fs/ext4/xattr.h
... | ... | @@ -150,6 +150,10 @@ |
150 | 150 | loff_t pos, unsigned len, |
151 | 151 | unsigned copied, |
152 | 152 | struct page *page); |
153 | +extern struct buffer_head * | |
154 | +ext4_journalled_write_inline_data(struct inode *inode, | |
155 | + unsigned len, | |
156 | + struct page *page); | |
153 | 157 | # else /* CONFIG_EXT4_FS_XATTR */ |
154 | 158 | |
155 | 159 | static inline int |
... | ... | @@ -287,6 +291,14 @@ |
287 | 291 | struct page *page) |
288 | 292 | { |
289 | 293 | return 0; |
294 | +} | |
295 | + | |
296 | +static inline struct buffer_head * | |
297 | +ext4_journalled_write_inline_data(struct inode *inode, | |
298 | + unsigned len, | |
299 | + struct page *page) | |
300 | +{ | |
301 | + return NULL; | |
290 | 302 | } |
291 | 303 | # endif /* CONFIG_EXT4_FS_XATTR */ |
292 | 304 |