Commit aef1c8513c1f8ae076e22ea2a57eff5835578e75

Authored by Tao Ma
Committed by Theodore Ts'o
1 parent 0d812f77b3

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>

Showing 3 changed files with 107 additions and 0 deletions Side-by-side Diff

... ... @@ -1753,4 +1753,94 @@
1753 1753 brelse(iloc.bh);
1754 1754 return error;
1755 1755 }
  1756 +
  1757 +void 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 +
  1829 +out_error:
  1830 + up_write(&EXT4_I(inode)->i_data_sem);
  1831 +out:
  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 +}
... ... @@ -3594,6 +3594,14 @@
3594 3594 if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC))
3595 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 3605 if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
3598 3606 ext4_ext_truncate(inode);
3599 3607 else
... ... @@ -190,6 +190,8 @@
190 190 extern int ext4_try_to_evict_inline_data(handle_t *handle,
191 191 struct inode *inode,
192 192 int needed);
  193 +extern void ext4_inline_data_truncate(struct inode *inode, int *has_inline);
  194 +
193 195 # else /* CONFIG_EXT4_FS_XATTR */
194 196  
195 197 static inline int
... ... @@ -411,6 +413,13 @@
411 413 {
412 414 return 0;
413 415 }
  416 +
  417 +static inline void ext4_inline_data_truncate(struct inode *inode,
  418 + int *has_inline)
  419 +{
  420 + return;
  421 +}
  422 +
414 423 # endif /* CONFIG_EXT4_FS_XATTR */
415 424  
416 425 #ifdef CONFIG_EXT4_FS_SECURITY