aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@redhat.com>2009-05-06 19:02:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-05-06 19:36:09 -0400
commitdf3935ffd6166fdd00702cf548fb5bb55737758b (patch)
treeb220111452403aba3affa1fbbc03d2927d3787aa
parent57adc4d2dbf968fdbe516359688094eef4d46581 (diff)
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>
-rw-r--r--fs/ioctl.c75
1 files changed, 55 insertions, 20 deletions
diff --git a/fs/ioctl.c b/fs/ioctl.c
index ac2d47e43926..82d9c42b8bac 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -258,7 +258,7 @@ int __generic_block_fiemap(struct inode *inode,
258 long long length = 0, map_len = 0; 258 long long length = 0, map_len = 0;
259 u64 logical = 0, phys = 0, size = 0; 259 u64 logical = 0, phys = 0, size = 0;
260 u32 flags = FIEMAP_EXTENT_MERGED; 260 u32 flags = FIEMAP_EXTENT_MERGED;
261 int ret = 0; 261 int ret = 0, past_eof = 0, whole_file = 0;
262 262
263 if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC))) 263 if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC)))
264 return ret; 264 return ret;
@@ -266,6 +266,9 @@ int __generic_block_fiemap(struct inode *inode,
266 start_blk = logical_to_blk(inode, start); 266 start_blk = logical_to_blk(inode, start);
267 267
268 length = (long long)min_t(u64, len, i_size_read(inode)); 268 length = (long long)min_t(u64, len, i_size_read(inode));
269 if (length < len)
270 whole_file = 1;
271
269 map_len = length; 272 map_len = length;
270 273
271 do { 274 do {
@@ -282,11 +285,26 @@ int __generic_block_fiemap(struct inode *inode,
282 285
283 /* HOLE */ 286 /* HOLE */
284 if (!buffer_mapped(&tmp)) { 287 if (!buffer_mapped(&tmp)) {
288 length -= blk_to_logical(inode, 1);
289 start_blk++;
290
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
285 /* 303 /*
286 * first hole after going past the EOF, this is our 304 * first hole after going past the EOF, this is our
287 * last extent 305 * last extent
288 */ 306 */
289 if (length <= 0) { 307 if (past_eof && size) {
290 flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST; 308 flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST;
291 ret = fiemap_fill_next_extent(fieinfo, logical, 309 ret = fiemap_fill_next_extent(fieinfo, logical,
292 phys, size, 310 phys, size,
@@ -294,15 +312,37 @@ int __generic_block_fiemap(struct inode *inode,
294 break; 312 break;
295 } 313 }
296 314
297 length -= blk_to_logical(inode, 1);
298
299 /* if we have holes up to/past EOF then we're done */ 315 /* if we have holes up to/past EOF then we're done */
300 if (length <= 0) 316 if (length <= 0 || past_eof)
301 break; 317 break;
302
303 start_blk++;
304 } else { 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) {
335 ret = fiemap_fill_next_extent(fieinfo, logical,
336 phys, size,
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) {
306 ret = fiemap_fill_next_extent(fieinfo, logical, 346 ret = fiemap_fill_next_extent(fieinfo, logical,
307 phys, size, 347 phys, size,
308 flags); 348 flags);
@@ -319,19 +359,14 @@ int __generic_block_fiemap(struct inode *inode,
319 start_blk += logical_to_blk(inode, size); 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 362 * If we are past the EOF, then we need to make sure as
323 * if there is a hole so we can mark this extent as the 363 * soon as we find a hole that the last extent we found
324 * last one, and if not keep mapping things until we 364 * is marked with FIEMAP_EXTENT_LAST
325 * find a hole, or we run out of slots in the extent
326 * array
327 */ 365 */
328 if (length <= 0) 366 if (!past_eof &&
329 continue; 367 logical+size >=
330 368 blk_to_logical(inode, 0)+i_size_read(inode))
331 ret = fiemap_fill_next_extent(fieinfo, logical, phys, 369 past_eof = 1;
332 size, flags);
333 if (ret)
334 break;
335 } 370 }
336 cond_resched(); 371 cond_resched();
337 } while (1); 372 } while (1);