diff options
author | Dmitry Monakhov <dmonakhov@openvz.org> | 2014-12-02 16:11:20 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2014-12-02 16:11:20 -0500 |
commit | d952d69e268f833c85c0bafee9f67f9dba85044b (patch) | |
tree | 8292c9e39fa90e279a9e1698f894d400579b6c5b /fs/ext4 | |
parent | 5cc28a9eaab21ce7ded7845b32e2eafc4bbeb175 (diff) |
ext4: ext4_inline_data_fiemap should respect callers argument
Currently ext4_inline_data_fiemap ignores requested arguments (start
and len) which may lead endless loop if start != 0. Also fix incorrect
extent length determination.
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/ext4.h | 2 | ||||
-rw-r--r-- | fs/ext4/extents.c | 3 | ||||
-rw-r--r-- | fs/ext4/inline.c | 19 |
3 files changed, 16 insertions, 8 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 4186ec84f835..c24665ead8d1 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -2634,7 +2634,7 @@ extern struct buffer_head *ext4_get_first_inline_block(struct inode *inode, | |||
2634 | int *retval); | 2634 | int *retval); |
2635 | extern int ext4_inline_data_fiemap(struct inode *inode, | 2635 | extern int ext4_inline_data_fiemap(struct inode *inode, |
2636 | struct fiemap_extent_info *fieinfo, | 2636 | struct fiemap_extent_info *fieinfo, |
2637 | int *has_inline); | 2637 | int *has_inline, __u64 start, __u64 len); |
2638 | extern int ext4_try_to_evict_inline_data(handle_t *handle, | 2638 | extern int ext4_try_to_evict_inline_data(handle_t *handle, |
2639 | struct inode *inode, | 2639 | struct inode *inode, |
2640 | int needed); | 2640 | int needed); |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index c3a1fa1398f5..bed43081720f 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -5151,7 +5151,8 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
5151 | if (ext4_has_inline_data(inode)) { | 5151 | if (ext4_has_inline_data(inode)) { |
5152 | int has_inline = 1; | 5152 | int has_inline = 1; |
5153 | 5153 | ||
5154 | error = ext4_inline_data_fiemap(inode, fieinfo, &has_inline); | 5154 | error = ext4_inline_data_fiemap(inode, fieinfo, &has_inline, |
5155 | start, len); | ||
5155 | 5156 | ||
5156 | if (has_inline) | 5157 | if (has_inline) |
5157 | return error; | 5158 | return error; |
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index efdcede40c22..b32d77bfb3a1 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c | |||
@@ -1808,11 +1808,12 @@ int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) | |||
1808 | 1808 | ||
1809 | int ext4_inline_data_fiemap(struct inode *inode, | 1809 | int ext4_inline_data_fiemap(struct inode *inode, |
1810 | struct fiemap_extent_info *fieinfo, | 1810 | struct fiemap_extent_info *fieinfo, |
1811 | int *has_inline) | 1811 | int *has_inline, __u64 start, __u64 len) |
1812 | { | 1812 | { |
1813 | __u64 physical = 0; | 1813 | __u64 physical = 0; |
1814 | __u64 length; | 1814 | __u64 inline_len; |
1815 | __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_LAST; | 1815 | __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED | |
1816 | FIEMAP_EXTENT_LAST; | ||
1816 | int error = 0; | 1817 | int error = 0; |
1817 | struct ext4_iloc iloc; | 1818 | struct ext4_iloc iloc; |
1818 | 1819 | ||
@@ -1821,6 +1822,13 @@ int ext4_inline_data_fiemap(struct inode *inode, | |||
1821 | *has_inline = 0; | 1822 | *has_inline = 0; |
1822 | goto out; | 1823 | goto out; |
1823 | } | 1824 | } |
1825 | inline_len = min_t(size_t, ext4_get_inline_size(inode), | ||
1826 | i_size_read(inode)); | ||
1827 | if (start >= inline_len) | ||
1828 | goto out; | ||
1829 | if (start + len < inline_len) | ||
1830 | inline_len = start + len; | ||
1831 | inline_len -= start; | ||
1824 | 1832 | ||
1825 | error = ext4_get_inode_loc(inode, &iloc); | 1833 | error = ext4_get_inode_loc(inode, &iloc); |
1826 | if (error) | 1834 | if (error) |
@@ -1829,11 +1837,10 @@ int ext4_inline_data_fiemap(struct inode *inode, | |||
1829 | physical = (__u64)iloc.bh->b_blocknr << inode->i_sb->s_blocksize_bits; | 1837 | physical = (__u64)iloc.bh->b_blocknr << inode->i_sb->s_blocksize_bits; |
1830 | physical += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data; | 1838 | physical += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data; |
1831 | physical += offsetof(struct ext4_inode, i_block); | 1839 | physical += offsetof(struct ext4_inode, i_block); |
1832 | length = i_size_read(inode); | ||
1833 | 1840 | ||
1834 | if (physical) | 1841 | if (physical) |
1835 | error = fiemap_fill_next_extent(fieinfo, 0, physical, | 1842 | error = fiemap_fill_next_extent(fieinfo, start, physical, |
1836 | length, flags); | 1843 | inline_len, flags); |
1837 | brelse(iloc.bh); | 1844 | brelse(iloc.bh); |
1838 | out: | 1845 | out: |
1839 | up_read(&EXT4_I(inode)->xattr_sem); | 1846 | up_read(&EXT4_I(inode)->xattr_sem); |