aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTao Ma <boyu.mt@taobao.com>2012-12-10 14:06:03 -0500
committerTheodore Ts'o <tytso@mit.edu>2012-12-10 14:06:03 -0500
commit0c8d414f163f5d35e43a4de7a6e5ee8c253fcccf (patch)
tree7db57d3b2926408bda5bad880896ee4ec384f398 /fs
parentaef1c8513c1f8ae076e22ea2a57eff5835578e75 (diff)
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/extents.c4
-rw-r--r--fs/ext4/inline.c39
-rw-r--r--fs/ext4/xattr.h5
3 files changed, 48 insertions, 0 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 70dc6fc53a00..d45ff3faefc6 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4399,6 +4399,10 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
4399 if (mode & FALLOC_FL_PUNCH_HOLE) 4399 if (mode & FALLOC_FL_PUNCH_HOLE)
4400 return ext4_punch_hole(file, offset, len); 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 trace_ext4_fallocate_enter(inode, offset, len, mode); 4406 trace_ext4_fallocate_enter(inode, offset, len, mode);
4403 map.m_lblk = offset >> blkbits; 4407 map.m_lblk = offset >> blkbits;
4404 /* 4408 /*
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 727edb8d57e0..53b2f65091dd 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1843,3 +1843,42 @@ out:
1843 ext4_journal_stop(handle); 1843 ext4_journal_stop(handle);
1844 return; 1844 return;
1845} 1845}
1846
1847int 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);
1879out:
1880 ext4_journal_stop(handle);
1881out_free:
1882 brelse(iloc.bh);
1883 return error;
1884}
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index 1a71a97e14ad..4222388c772f 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -192,6 +192,7 @@ extern int ext4_try_to_evict_inline_data(handle_t *handle,
192 int needed); 192 int needed);
193extern void ext4_inline_data_truncate(struct inode *inode, int *has_inline); 193extern void ext4_inline_data_truncate(struct inode *inode, int *has_inline);
194 194
195extern int ext4_convert_inline_data(struct inode *inode);
195# else /* CONFIG_EXT4_FS_XATTR */ 196# else /* CONFIG_EXT4_FS_XATTR */
196 197
197static inline int 198static inline int
@@ -420,6 +421,10 @@ static inline void ext4_inline_data_truncate(struct inode *inode,
420 return; 421 return;
421} 422}
422 423
424static inline int ext4_convert_inline_data(struct inode *inode)
425{
426 return 0;
427}
423# endif /* CONFIG_EXT4_FS_XATTR */ 428# endif /* CONFIG_EXT4_FS_XATTR */
424 429
425#ifdef CONFIG_EXT4_FS_SECURITY 430#ifdef CONFIG_EXT4_FS_SECURITY