forked from Minki/linux
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: Fan li <fanofcode.li@samsung.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
6d5a1495ee
commit
9a950d52b7
@ -783,7 +783,6 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
loff_t isize = i_size_read(inode);
|
||||
u64 logical = 0, phys = 0, size = 0;
|
||||
u32 flags = 0;
|
||||
bool past_eof = false, whole_file = false;
|
||||
int ret = 0;
|
||||
|
||||
ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
|
||||
@ -797,17 +796,18 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
}
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
if (start >= isize)
|
||||
goto out;
|
||||
|
||||
if (len >= isize) {
|
||||
whole_file = true;
|
||||
len = isize;
|
||||
}
|
||||
if (start + len > isize)
|
||||
len = isize - start;
|
||||
|
||||
if (logical_to_blk(inode, len) == 0)
|
||||
len = blk_to_logical(inode, 1);
|
||||
|
||||
start_blk = logical_to_blk(inode, start);
|
||||
last_blk = logical_to_blk(inode, start + len - 1);
|
||||
|
||||
next:
|
||||
memset(&map_bh, 0, sizeof(struct buffer_head));
|
||||
map_bh.b_size = len;
|
||||
@ -819,59 +819,33 @@ next:
|
||||
|
||||
/* HOLE */
|
||||
if (!buffer_mapped(&map_bh)) {
|
||||
start_blk++;
|
||||
|
||||
if (!past_eof && blk_to_logical(inode, start_blk) >= isize)
|
||||
past_eof = 1;
|
||||
|
||||
if (past_eof && size) {
|
||||
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 (start_blk > last_blk || past_eof || ret)
|
||||
goto out;
|
||||
} else {
|
||||
if (start_blk > last_blk && !whole_file) {
|
||||
ret = fiemap_fill_next_extent(fieinfo, logical,
|
||||
phys, size, flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* if size != 0 then we know we already have an extent
|
||||
* to add, so add it.
|
||||
/* Go through holes util pass the EOF */
|
||||
if (blk_to_logical(inode, start_blk++) < isize)
|
||||
goto prep_next;
|
||||
/* Found a hole beyond isize means no more extents.
|
||||
* Note that the premise is that filesystems don't
|
||||
* punch holes beyond isize and keep size unchanged.
|
||||
*/
|
||||
if (size) {
|
||||
ret = fiemap_fill_next_extent(fieinfo, logical,
|
||||
phys, size, flags);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
logical = blk_to_logical(inode, start_blk);
|
||||
phys = blk_to_logical(inode, map_bh.b_blocknr);
|
||||
size = map_bh.b_size;
|
||||
flags = 0;
|
||||
if (buffer_unwritten(&map_bh))
|
||||
flags = FIEMAP_EXTENT_UNWRITTEN;
|
||||
|
||||
start_blk += logical_to_blk(inode, size);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
flags |= FIEMAP_EXTENT_LAST;
|
||||
}
|
||||
|
||||
if (size)
|
||||
ret = fiemap_fill_next_extent(fieinfo, logical,
|
||||
phys, size, flags);
|
||||
|
||||
if (start_blk > last_blk || ret)
|
||||
goto out;
|
||||
|
||||
logical = blk_to_logical(inode, start_blk);
|
||||
phys = blk_to_logical(inode, map_bh.b_blocknr);
|
||||
size = map_bh.b_size;
|
||||
flags = 0;
|
||||
if (buffer_unwritten(&map_bh))
|
||||
flags = FIEMAP_EXTENT_UNWRITTEN;
|
||||
|
||||
start_blk += logical_to_blk(inode, size);
|
||||
|
||||
prep_next:
|
||||
cond_resched();
|
||||
if (fatal_signal_pending(current))
|
||||
ret = -EINTR;
|
||||
|
Loading…
Reference in New Issue
Block a user