Commit 0c8d414f163f5d35e43a4de7a6e5ee8c253fcccf
Committed by
Theodore Ts'o
1 parent
aef1c8513c
Exists in
master
and in
20 other branches
ext4: let fallocate handle inline data correctly
If we are punching hole in a file, we will return ENOTSUPP. As for the fallocation of some extents, we will convert the inline data to a normal extent based file first. Signed-off-by: Tao Ma <boyu.mt@taobao.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Showing 3 changed files with 48 additions and 0 deletions Side-by-side Diff
fs/ext4/extents.c
... | ... | @@ -4399,6 +4399,10 @@ |
4399 | 4399 | if (mode & FALLOC_FL_PUNCH_HOLE) |
4400 | 4400 | return ext4_punch_hole(file, offset, len); |
4401 | 4401 | |
4402 | + ret = ext4_convert_inline_data(inode); | |
4403 | + if (ret) | |
4404 | + return ret; | |
4405 | + | |
4402 | 4406 | trace_ext4_fallocate_enter(inode, offset, len, mode); |
4403 | 4407 | map.m_lblk = offset >> blkbits; |
4404 | 4408 | /* |
fs/ext4/inline.c
... | ... | @@ -1843,4 +1843,43 @@ |
1843 | 1843 | ext4_journal_stop(handle); |
1844 | 1844 | return; |
1845 | 1845 | } |
1846 | + | |
1847 | +int ext4_convert_inline_data(struct inode *inode) | |
1848 | +{ | |
1849 | + int error, needed_blocks; | |
1850 | + handle_t *handle; | |
1851 | + struct ext4_iloc iloc; | |
1852 | + | |
1853 | + if (!ext4_has_inline_data(inode)) { | |
1854 | + ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); | |
1855 | + return 0; | |
1856 | + } | |
1857 | + | |
1858 | + needed_blocks = ext4_writepage_trans_blocks(inode); | |
1859 | + | |
1860 | + iloc.bh = NULL; | |
1861 | + error = ext4_get_inode_loc(inode, &iloc); | |
1862 | + if (error) | |
1863 | + return error; | |
1864 | + | |
1865 | + handle = ext4_journal_start(inode, needed_blocks); | |
1866 | + if (IS_ERR(handle)) { | |
1867 | + error = PTR_ERR(handle); | |
1868 | + goto out_free; | |
1869 | + } | |
1870 | + | |
1871 | + down_write(&EXT4_I(inode)->xattr_sem); | |
1872 | + if (!ext4_has_inline_data(inode)) { | |
1873 | + up_write(&EXT4_I(inode)->xattr_sem); | |
1874 | + goto out; | |
1875 | + } | |
1876 | + | |
1877 | + error = ext4_convert_inline_data_nolock(handle, inode, &iloc); | |
1878 | + up_write(&EXT4_I(inode)->xattr_sem); | |
1879 | +out: | |
1880 | + ext4_journal_stop(handle); | |
1881 | +out_free: | |
1882 | + brelse(iloc.bh); | |
1883 | + return error; | |
1884 | +} |
fs/ext4/xattr.h
... | ... | @@ -192,6 +192,7 @@ |
192 | 192 | int needed); |
193 | 193 | extern void ext4_inline_data_truncate(struct inode *inode, int *has_inline); |
194 | 194 | |
195 | +extern int ext4_convert_inline_data(struct inode *inode); | |
195 | 196 | # else /* CONFIG_EXT4_FS_XATTR */ |
196 | 197 | |
197 | 198 | static inline int |
... | ... | @@ -420,6 +421,10 @@ |
420 | 421 | return; |
421 | 422 | } |
422 | 423 | |
424 | +static inline int ext4_convert_inline_data(struct inode *inode) | |
425 | +{ | |
426 | + return 0; | |
427 | +} | |
423 | 428 | # endif /* CONFIG_EXT4_FS_XATTR */ |
424 | 429 | |
425 | 430 | #ifdef CONFIG_EXT4_FS_SECURITY |