f2fs: fix bugs and simplify codes of f2fs_fiemap
authorFan Li <fanofcode.li@samsung.com>
Sat, 26 Dec 2015 10:07:41 +0000 (18:07 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 30 Dec 2015 18:14:16 +0000 (10:14 -0800)
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>
fs/f2fs/data.c

index 5c43b2d606ec7afd5bf9722b16532f77594c2d56..d67c599510d9bfb6c5f7c93e092dca99af291538 100644 (file)
@@ -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;
-               }
+               /* 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.
+                */
+               flags |= FIEMAP_EXTENT_LAST;
+       }
 
-               /* 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)
+               ret = fiemap_fill_next_extent(fieinfo, logical,
+                               phys, size, flags);
 
-               /*
-                * 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;
-               }
+       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;
+       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);
+       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;
-       }
+prep_next:
        cond_resched();
        if (fatal_signal_pending(current))
                ret = -EINTR;