diff options
author | Dmitry Monakhov <dmonakhov@openvz.org> | 2014-12-02 22:11:20 +0100 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2014-12-02 22:11:20 +0100 |
commit | d952d69e268f833c85c0bafee9f67f9dba85044b (patch) | |
tree | 8292c9e39fa90e279a9e1698f894d400579b6c5b | |
parent | ext4: prevent fsreentrance deadlock for inline_data (diff) | |
download | linux-d952d69e268f833c85c0bafee9f67f9dba85044b.tar.xz linux-d952d69e268f833c85c0bafee9f67f9dba85044b.zip |
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>
-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, int *retval); extern int ext4_inline_data_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - int *has_inline); + int *has_inline, __u64 start, __u64 len); extern int ext4_try_to_evict_inline_data(handle_t *handle, struct inode *inode, 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, if (ext4_has_inline_data(inode)) { int has_inline = 1; - error = ext4_inline_data_fiemap(inode, fieinfo, &has_inline); + error = ext4_inline_data_fiemap(inode, fieinfo, &has_inline, + start, len); if (has_inline) 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) int ext4_inline_data_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - int *has_inline) + int *has_inline, __u64 start, __u64 len) { __u64 physical = 0; - __u64 length; - __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_LAST; + __u64 inline_len; + __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED | + FIEMAP_EXTENT_LAST; int error = 0; struct ext4_iloc iloc; @@ -1821,6 +1822,13 @@ int ext4_inline_data_fiemap(struct inode *inode, *has_inline = 0; goto out; } + inline_len = min_t(size_t, ext4_get_inline_size(inode), + i_size_read(inode)); + if (start >= inline_len) + goto out; + if (start + len < inline_len) + inline_len = start + len; + inline_len -= start; error = ext4_get_inode_loc(inode, &iloc); if (error) @@ -1829,11 +1837,10 @@ int ext4_inline_data_fiemap(struct inode *inode, physical = (__u64)iloc.bh->b_blocknr << inode->i_sb->s_blocksize_bits; physical += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data; physical += offsetof(struct ext4_inode, i_block); - length = i_size_read(inode); if (physical) - error = fiemap_fill_next_extent(fieinfo, 0, physical, - length, flags); + error = fiemap_fill_next_extent(fieinfo, start, physical, + inline_len, flags); brelse(iloc.bh); out: up_read(&EXT4_I(inode)->xattr_sem); |