Commit df3935ffd6166fdd00702cf548fb5bb55737758b

Authored by Josef Bacik
Committed by Linus Torvalds
1 parent 57adc4d2db

fiemap: fix problem with setting FIEMAP_EXTENT_LAST

Fix a problem where the generic block based fiemap stuff would not
properly set FIEMAP_EXTENT_LAST on the last extent.  I've reworked things
to keep track if we go past the EOF, and mark the last extent properly.
The problem was reported by and tested by Eric Sandeen.

Tested-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Josef Bacik <jbacik@redhat.com>
Cc: <linux-ext4@vger.kernel.org>
Cc: <xfs-masters@oss.sgi.com>
Cc: <linux-btrfs@vger.kernel.org>
Cc: Steven Whitehouse <swhiteho@redhat.com>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <Joel.Becker@oracle.com>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 55 additions and 20 deletions Side-by-side Diff

... ... @@ -258,7 +258,7 @@
258 258 long long length = 0, map_len = 0;
259 259 u64 logical = 0, phys = 0, size = 0;
260 260 u32 flags = FIEMAP_EXTENT_MERGED;
261   - int ret = 0;
  261 + int ret = 0, past_eof = 0, whole_file = 0;
262 262  
263 263 if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC)))
264 264 return ret;
... ... @@ -266,6 +266,9 @@
266 266 start_blk = logical_to_blk(inode, start);
267 267  
268 268 length = (long long)min_t(u64, len, i_size_read(inode));
  269 + if (length < len)
  270 + whole_file = 1;
  271 +
269 272 map_len = length;
270 273  
271 274 do {
272 275  
273 276  
... ... @@ -282,11 +285,26 @@
282 285  
283 286 /* HOLE */
284 287 if (!buffer_mapped(&tmp)) {
  288 + length -= blk_to_logical(inode, 1);
  289 + start_blk++;
  290 +
285 291 /*
  292 + * we want to handle the case where there is an
  293 + * allocated block at the front of the file, and then
  294 + * nothing but holes up to the end of the file properly,
  295 + * to make sure that extent at the front gets properly
  296 + * marked with FIEMAP_EXTENT_LAST
  297 + */
  298 + if (!past_eof &&
  299 + blk_to_logical(inode, start_blk) >=
  300 + blk_to_logical(inode, 0)+i_size_read(inode))
  301 + past_eof = 1;
  302 +
  303 + /*
286 304 * first hole after going past the EOF, this is our
287 305 * last extent
288 306 */
289   - if (length <= 0) {
  307 + if (past_eof && size) {
290 308 flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST;
291 309 ret = fiemap_fill_next_extent(fieinfo, logical,
292 310 phys, size,
293 311  
294 312  
295 313  
296 314  
... ... @@ -294,18 +312,40 @@
294 312 break;
295 313 }
296 314  
297   - length -= blk_to_logical(inode, 1);
298   -
299 315 /* if we have holes up to/past EOF then we're done */
300   - if (length <= 0)
  316 + if (length <= 0 || past_eof)
301 317 break;
302   -
303   - start_blk++;
304 318 } else {
305   - if (length <= 0 && size) {
  319 + /*
  320 + * we have gone over the length of what we wanted to
  321 + * map, and it wasn't the entire file, so add the extent
  322 + * we got last time and exit.
  323 + *
  324 + * This is for the case where say we want to map all the
  325 + * way up to the second to the last block in a file, but
  326 + * the last block is a hole, making the second to last
  327 + * block FIEMAP_EXTENT_LAST. In this case we want to
  328 + * see if there is a hole after the second to last block
  329 + * so we can mark it properly. If we found data after
  330 + * we exceeded the length we were requesting, then we
  331 + * are good to go, just add the extent to the fieinfo
  332 + * and break
  333 + */
  334 + if (length <= 0 && !whole_file) {
306 335 ret = fiemap_fill_next_extent(fieinfo, logical,
307 336 phys, size,
308 337 flags);
  338 + break;
  339 + }
  340 +
  341 + /*
  342 + * if size != 0 then we know we already have an extent
  343 + * to add, so add it.
  344 + */
  345 + if (size) {
  346 + ret = fiemap_fill_next_extent(fieinfo, logical,
  347 + phys, size,
  348 + flags);
309 349 if (ret)
310 350 break;
311 351 }
312 352  
... ... @@ -319,19 +359,14 @@
319 359 start_blk += logical_to_blk(inode, size);
320 360  
321 361 /*
322   - * if we are past the EOF we need to loop again to see
323   - * if there is a hole so we can mark this extent as the
324   - * last one, and if not keep mapping things until we
325   - * find a hole, or we run out of slots in the extent
326   - * array
  362 + * If we are past the EOF, then we need to make sure as
  363 + * soon as we find a hole that the last extent we found
  364 + * is marked with FIEMAP_EXTENT_LAST
327 365 */
328   - if (length <= 0)
329   - continue;
330   -
331   - ret = fiemap_fill_next_extent(fieinfo, logical, phys,
332   - size, flags);
333   - if (ret)
334   - break;
  366 + if (!past_eof &&
  367 + logical+size >=
  368 + blk_to_logical(inode, 0)+i_size_read(inode))
  369 + past_eof = 1;
335 370 }
336 371 cond_resched();
337 372 } while (1);