diff options
Diffstat (limited to 'fs/ext4/inline.c')
-rw-r--r-- | fs/ext4/inline.c | 90 |
1 files changed, 90 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 | |||
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 | } | ||