Commit 9a950d52 authored by Fan Li's avatar Fan Li Committed by Jaegeuk Kim

f2fs: fix bugs and simplify codes of f2fs_fiemap

fix bugs:
1. len could be updated incorrectly when start+len is beyond isize.
2. If there is a hole consisting of more than two blocks, it could
   fail to add FIEMAP_EXTENT_LAST flag for the last extent.
3. If there is an extent beyond isize, when we search extents in a range
   that ends at isize, it will also return the extent beyond isize,
   which is outside the range.
Signed-off-by: default avatarFan li <fanofcode.li@samsung.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 6d5a1495
...@@ -783,7 +783,6 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -783,7 +783,6 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
loff_t isize = i_size_read(inode); loff_t isize = i_size_read(inode);
u64 logical = 0, phys = 0, size = 0; u64 logical = 0, phys = 0, size = 0;
u32 flags = 0; u32 flags = 0;
bool past_eof = false, whole_file = false;
int ret = 0; int ret = 0;
ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
...@@ -797,17 +796,18 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -797,17 +796,18 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
} }
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
if (start >= isize)
goto out;
if (len >= isize) { if (start + len > isize)
whole_file = true; len = isize - start;
len = isize;
}
if (logical_to_blk(inode, len) == 0) if (logical_to_blk(inode, len) == 0)
len = blk_to_logical(inode, 1); len = blk_to_logical(inode, 1);
start_blk = logical_to_blk(inode, start); start_blk = logical_to_blk(inode, start);
last_blk = logical_to_blk(inode, start + len - 1); last_blk = logical_to_blk(inode, start + len - 1);
next: next:
memset(&map_bh, 0, sizeof(struct buffer_head)); memset(&map_bh, 0, sizeof(struct buffer_head));
map_bh.b_size = len; map_bh.b_size = len;
...@@ -819,41 +819,22 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -819,41 +819,22 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
/* HOLE */ /* HOLE */
if (!buffer_mapped(&map_bh)) { if (!buffer_mapped(&map_bh)) {
start_blk++; /* Go through holes util pass the EOF */
if (blk_to_logical(inode, start_blk++) < isize)
if (!past_eof && blk_to_logical(inode, start_blk) >= isize) goto prep_next;
past_eof = 1; /* Found a hole beyond isize means no more extents.
* Note that the premise is that filesystems don't
if (past_eof && size) { * punch holes beyond isize and keep size unchanged.
*/
flags |= FIEMAP_EXTENT_LAST; flags |= FIEMAP_EXTENT_LAST;
ret = fiemap_fill_next_extent(fieinfo, logical,
phys, size, flags);
} else if (size) {
ret = fiemap_fill_next_extent(fieinfo, logical,
phys, size, flags);
size = 0;
} }
/* if we have holes up to/past EOF then we're done */ if (size)
if (start_blk > last_blk || past_eof || ret)
goto out;
} else {
if (start_blk > last_blk && !whole_file) {
ret = fiemap_fill_next_extent(fieinfo, logical, ret = fiemap_fill_next_extent(fieinfo, logical,
phys, size, flags); phys, size, flags);
goto out;
}
/* if (start_blk > last_blk || ret)
* if size != 0 then we know we already have an extent
* to add, so add it.
*/
if (size) {
ret = fiemap_fill_next_extent(fieinfo, logical,
phys, size, flags);
if (ret)
goto out; goto out;
}
logical = blk_to_logical(inode, start_blk); logical = blk_to_logical(inode, start_blk);
phys = blk_to_logical(inode, map_bh.b_blocknr); phys = blk_to_logical(inode, map_bh.b_blocknr);
...@@ -864,14 +845,7 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -864,14 +845,7 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
start_blk += logical_to_blk(inode, size); start_blk += logical_to_blk(inode, size);
/* prep_next:
* If we are past the EOF, then we need to make sure as
* soon as we find a hole that the last extent we found
* is marked with FIEMAP_EXTENT_LAST
*/
if (!past_eof && logical + size >= isize)
past_eof = true;
}
cond_resched(); cond_resched();
if (fatal_signal_pending(current)) if (fatal_signal_pending(current))
ret = -EINTR; ret = -EINTR;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment