aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorTao Ma <boyu.mt@taobao.com>2012-12-10 14:06:02 -0500
committerTheodore Ts'o <tytso@mit.edu>2012-12-10 14:06:02 -0500
commitaef1c8513c1f8ae076e22ea2a57eff5835578e75 (patch)
tree0738a2b503b1d7c6a43138bd87095901867e412e /fs/ext4
parent0d812f77b36c16dff692390508155de2c7f95ea3 (diff)
ext4: let ext4_truncate handle inline data correctly
Signed-off-by: Robin Dong <sanbai@taobao.com> Signed-off-by: Tao Ma <boyu.mt@taobao.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/inline.c90
-rw-r--r--fs/ext4/inode.c8
-rw-r--r--fs/ext4/xattr.h9
3 files changed, 107 insertions, 0 deletions
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index cec651e2646c..727edb8d57e0 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1753,3 +1753,93 @@ out:
1753 brelse(iloc.bh); 1753 brelse(iloc.bh);
1754 return error; 1754 return error;
1755} 1755}
1756
1757void ext4_inline_data_truncate(struct inode *inode, int *has_inline)
1758{
1759 handle_t *handle;
1760 int inline_size, value_len, needed_blocks;
1761 size_t i_size;
1762 void *value = NULL;
1763 struct ext4_xattr_ibody_find is = {
1764 .s = { .not_found = -ENODATA, },
1765 };
1766 struct ext4_xattr_info i = {
1767 .name_index = EXT4_XATTR_INDEX_SYSTEM,
1768 .name = EXT4_XATTR_SYSTEM_DATA,
1769 };
1770
1771
1772 needed_blocks = ext4_writepage_trans_blocks(inode);
1773 handle = ext4_journal_start(inode, needed_blocks);
1774 if (IS_ERR(handle))
1775 return;
1776
1777 down_write(&EXT4_I(inode)->xattr_sem);
1778 if (!ext4_has_inline_data(inode)) {
1779 *has_inline = 0;
1780 ext4_journal_stop(handle);
1781 return;
1782 }
1783
1784 if (ext4_orphan_add(handle, inode))
1785 goto out;
1786
1787 if (ext4_get_inode_loc(inode, &is.iloc))
1788 goto out;
1789
1790 down_write(&EXT4_I(inode)->i_data_sem);
1791 i_size = inode->i_size;
1792 inline_size = ext4_get_inline_size(inode);
1793 EXT4_I(inode)->i_disksize = i_size;
1794
1795 if (i_size < inline_size) {
1796 /* Clear the content in the xattr space. */
1797 if (inline_size > EXT4_MIN_INLINE_DATA_SIZE) {
1798 if (ext4_xattr_ibody_find(inode, &i, &is))
1799 goto out_error;
1800
1801 BUG_ON(is.s.not_found);
1802
1803 value_len = le32_to_cpu(is.s.here->e_value_size);
1804 value = kmalloc(value_len, GFP_NOFS);
1805 if (!value)
1806 goto out_error;
1807
1808 if (ext4_xattr_ibody_get(inode, i.name_index, i.name,
1809 value, value_len))
1810 goto out_error;
1811
1812 i.value = value;
1813 i.value_len = i_size > EXT4_MIN_INLINE_DATA_SIZE ?
1814 i_size - EXT4_MIN_INLINE_DATA_SIZE : 0;
1815 if (ext4_xattr_ibody_inline_set(handle, inode, &i, &is))
1816 goto out_error;
1817 }
1818
1819 /* Clear the content within i_blocks. */
1820 if (i_size < EXT4_MIN_INLINE_DATA_SIZE)
1821 memset(ext4_raw_inode(&is.iloc)->i_block + i_size, 0,
1822 EXT4_MIN_INLINE_DATA_SIZE - i_size);
1823
1824 EXT4_I(inode)->i_inline_size = i_size <
1825 EXT4_MIN_INLINE_DATA_SIZE ?
1826 EXT4_MIN_INLINE_DATA_SIZE : i_size;
1827 }
1828
1829out_error:
1830 up_write(&EXT4_I(inode)->i_data_sem);
1831out:
1832 brelse(is.iloc.bh);
1833 up_write(&EXT4_I(inode)->xattr_sem);
1834 kfree(value);
1835 if (inode->i_nlink)
1836 ext4_orphan_del(handle, inode);
1837
1838 inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
1839 ext4_mark_inode_dirty(handle, inode);
1840 if (IS_SYNC(inode))
1841 ext4_handle_sync(handle);
1842
1843 ext4_journal_stop(handle);
1844 return;
1845}
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index f16ae02599cd..cb1c1ab2720b 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3594,6 +3594,14 @@ void ext4_truncate(struct inode *inode)
3594 if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC)) 3594 if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC))
3595 ext4_set_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE); 3595 ext4_set_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE);
3596 3596
3597 if (ext4_has_inline_data(inode)) {
3598 int has_inline = 1;
3599
3600 ext4_inline_data_truncate(inode, &has_inline);
3601 if (has_inline)
3602 return;
3603 }
3604
3597 if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) 3605 if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
3598 ext4_ext_truncate(inode); 3606 ext4_ext_truncate(inode);
3599 else 3607 else
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index 1be243aab01b..1a71a97e14ad 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -190,6 +190,8 @@ extern int ext4_inline_data_fiemap(struct inode *inode,
190extern int ext4_try_to_evict_inline_data(handle_t *handle, 190extern int ext4_try_to_evict_inline_data(handle_t *handle,
191 struct inode *inode, 191 struct inode *inode,
192 int needed); 192 int needed);
193extern void ext4_inline_data_truncate(struct inode *inode, int *has_inline);
194
193# else /* CONFIG_EXT4_FS_XATTR */ 195# else /* CONFIG_EXT4_FS_XATTR */
194 196
195static inline int 197static inline int
@@ -411,6 +413,13 @@ static inline int ext4_inline_data_fiemap(struct inode *inode,
411{ 413{
412 return 0; 414 return 0;
413} 415}
416
417static inline void ext4_inline_data_truncate(struct inode *inode,
418 int *has_inline)
419{
420 return;
421}
422
414# endif /* CONFIG_EXT4_FS_XATTR */ 423# endif /* CONFIG_EXT4_FS_XATTR */
415 424
416#ifdef CONFIG_EXT4_FS_SECURITY 425#ifdef CONFIG_EXT4_FS_SECURITY