Commit ad7fefb109b0418bb4f16fc1176fd082f986698b
1 parent
011fa99404
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
Revert "ext4: fix suboptimal seek_{data,hole} extents traversial"
This reverts commit 14516bb7bb6ffbd49f35389f9ece3b2045ba5815. This was causing regression test failures with generic/285 with an ext3 filesystem using CONFIG_EXT4_USE_FOR_EXT23. Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Showing 2 changed files with 116 additions and 108 deletions Side-by-side Diff
fs/ext4/extents.c
... | ... | @@ -5166,8 +5166,8 @@ |
5166 | 5166 | |
5167 | 5167 | /* fallback to generic here if not in extents fmt */ |
5168 | 5168 | if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) |
5169 | - return __generic_block_fiemap(inode, fieinfo, start, len, | |
5170 | - ext4_get_block); | |
5169 | + return generic_block_fiemap(inode, fieinfo, start, len, | |
5170 | + ext4_get_block); | |
5171 | 5171 | |
5172 | 5172 | if (fiemap_check_flags(fieinfo, EXT4_FIEMAP_FLAGS)) |
5173 | 5173 | return -EBADR; |
fs/ext4/file.c
... | ... | @@ -273,20 +273,25 @@ |
273 | 273 | * we determine this extent as a data or a hole according to whether the |
274 | 274 | * page cache has data or not. |
275 | 275 | */ |
276 | -static int ext4_find_unwritten_pgoff(struct inode *inode, int whence, | |
277 | - loff_t endoff, loff_t *offset) | |
276 | +static int ext4_find_unwritten_pgoff(struct inode *inode, | |
277 | + int whence, | |
278 | + struct ext4_map_blocks *map, | |
279 | + loff_t *offset) | |
278 | 280 | { |
279 | 281 | struct pagevec pvec; |
282 | + unsigned int blkbits; | |
280 | 283 | pgoff_t index; |
281 | 284 | pgoff_t end; |
285 | + loff_t endoff; | |
282 | 286 | loff_t startoff; |
283 | 287 | loff_t lastoff; |
284 | 288 | int found = 0; |
285 | 289 | |
290 | + blkbits = inode->i_sb->s_blocksize_bits; | |
286 | 291 | startoff = *offset; |
287 | 292 | lastoff = startoff; |
293 | + endoff = (loff_t)(map->m_lblk + map->m_len) << blkbits; | |
288 | 294 | |
289 | - | |
290 | 295 | index = startoff >> PAGE_CACHE_SHIFT; |
291 | 296 | end = endoff >> PAGE_CACHE_SHIFT; |
292 | 297 | |
293 | 298 | |
294 | 299 | |
295 | 300 | |
296 | 301 | |
297 | 302 | |
298 | 303 | |
299 | 304 | |
300 | 305 | |
301 | 306 | |
302 | 307 | |
303 | 308 | |
304 | 309 | |
305 | 310 | |
306 | 311 | |
307 | 312 | |
308 | 313 | |
309 | 314 | |
310 | 315 | |
311 | 316 | |
312 | 317 | |
313 | 318 | |
314 | 319 | |
315 | 320 | |
... | ... | @@ -403,144 +408,147 @@ |
403 | 408 | static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize) |
404 | 409 | { |
405 | 410 | struct inode *inode = file->f_mapping->host; |
406 | - struct fiemap_extent_info fie; | |
407 | - struct fiemap_extent ext[2]; | |
408 | - loff_t next; | |
409 | - int i, ret = 0; | |
411 | + struct ext4_map_blocks map; | |
412 | + struct extent_status es; | |
413 | + ext4_lblk_t start, last, end; | |
414 | + loff_t dataoff, isize; | |
415 | + int blkbits; | |
416 | + int ret = 0; | |
410 | 417 | |
411 | 418 | mutex_lock(&inode->i_mutex); |
412 | - if (offset >= inode->i_size) { | |
419 | + | |
420 | + isize = i_size_read(inode); | |
421 | + if (offset >= isize) { | |
413 | 422 | mutex_unlock(&inode->i_mutex); |
414 | 423 | return -ENXIO; |
415 | 424 | } |
416 | - fie.fi_flags = 0; | |
417 | - fie.fi_extents_max = 2; | |
418 | - fie.fi_extents_start = (struct fiemap_extent __user *) &ext; | |
419 | - while (1) { | |
420 | - mm_segment_t old_fs = get_fs(); | |
421 | 425 | |
422 | - fie.fi_extents_mapped = 0; | |
423 | - memset(ext, 0, sizeof(*ext) * fie.fi_extents_max); | |
426 | + blkbits = inode->i_sb->s_blocksize_bits; | |
427 | + start = offset >> blkbits; | |
428 | + last = start; | |
429 | + end = isize >> blkbits; | |
430 | + dataoff = offset; | |
424 | 431 | |
425 | - set_fs(get_ds()); | |
426 | - ret = ext4_fiemap(inode, &fie, offset, maxsize - offset); | |
427 | - set_fs(old_fs); | |
428 | - if (ret) | |
432 | + do { | |
433 | + map.m_lblk = last; | |
434 | + map.m_len = end - last + 1; | |
435 | + ret = ext4_map_blocks(NULL, inode, &map, 0); | |
436 | + if (ret > 0 && !(map.m_flags & EXT4_MAP_UNWRITTEN)) { | |
437 | + if (last != start) | |
438 | + dataoff = (loff_t)last << blkbits; | |
429 | 439 | break; |
440 | + } | |
430 | 441 | |
431 | - /* No extents found, EOF */ | |
432 | - if (!fie.fi_extents_mapped) { | |
433 | - ret = -ENXIO; | |
442 | + /* | |
443 | + * If there is a delay extent at this offset, | |
444 | + * it will be as a data. | |
445 | + */ | |
446 | + ext4_es_find_delayed_extent_range(inode, last, last, &es); | |
447 | + if (es.es_len != 0 && in_range(last, es.es_lblk, es.es_len)) { | |
448 | + if (last != start) | |
449 | + dataoff = (loff_t)last << blkbits; | |
434 | 450 | break; |
435 | 451 | } |
436 | - for (i = 0; i < fie.fi_extents_mapped; i++) { | |
437 | - next = (loff_t)(ext[i].fe_length + ext[i].fe_logical); | |
438 | 452 | |
439 | - if (offset < (loff_t)ext[i].fe_logical) | |
440 | - offset = (loff_t)ext[i].fe_logical; | |
441 | - /* | |
442 | - * If extent is not unwritten, then it contains valid | |
443 | - * data, mapped or delayed. | |
444 | - */ | |
445 | - if (!(ext[i].fe_flags & FIEMAP_EXTENT_UNWRITTEN)) | |
446 | - goto out; | |
453 | + /* | |
454 | + * If there is a unwritten extent at this offset, | |
455 | + * it will be as a data or a hole according to page | |
456 | + * cache that has data or not. | |
457 | + */ | |
458 | + if (map.m_flags & EXT4_MAP_UNWRITTEN) { | |
459 | + int unwritten; | |
460 | + unwritten = ext4_find_unwritten_pgoff(inode, SEEK_DATA, | |
461 | + &map, &dataoff); | |
462 | + if (unwritten) | |
463 | + break; | |
464 | + } | |
447 | 465 | |
448 | - /* | |
449 | - * If there is a unwritten extent at this offset, | |
450 | - * it will be as a data or a hole according to page | |
451 | - * cache that has data or not. | |
452 | - */ | |
453 | - if (ext4_find_unwritten_pgoff(inode, SEEK_DATA, | |
454 | - next, &offset)) | |
455 | - goto out; | |
466 | + last++; | |
467 | + dataoff = (loff_t)last << blkbits; | |
468 | + } while (last <= end); | |
456 | 469 | |
457 | - if (ext[i].fe_flags & FIEMAP_EXTENT_LAST) { | |
458 | - ret = -ENXIO; | |
459 | - goto out; | |
460 | - } | |
461 | - offset = next; | |
462 | - } | |
463 | - } | |
464 | - if (offset > inode->i_size) | |
465 | - offset = inode->i_size; | |
466 | -out: | |
467 | 470 | mutex_unlock(&inode->i_mutex); |
468 | - if (ret) | |
469 | - return ret; | |
470 | 471 | |
471 | - return vfs_setpos(file, offset, maxsize); | |
472 | + if (dataoff > isize) | |
473 | + return -ENXIO; | |
474 | + | |
475 | + return vfs_setpos(file, dataoff, maxsize); | |
472 | 476 | } |
473 | 477 | |
474 | 478 | /* |
475 | - * ext4_seek_hole() retrieves the offset for SEEK_HOLE | |
479 | + * ext4_seek_hole() retrieves the offset for SEEK_HOLE. | |
476 | 480 | */ |
477 | 481 | static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize) |
478 | 482 | { |
479 | 483 | struct inode *inode = file->f_mapping->host; |
480 | - struct fiemap_extent_info fie; | |
481 | - struct fiemap_extent ext[2]; | |
482 | - loff_t next; | |
483 | - int i, ret = 0; | |
484 | + struct ext4_map_blocks map; | |
485 | + struct extent_status es; | |
486 | + ext4_lblk_t start, last, end; | |
487 | + loff_t holeoff, isize; | |
488 | + int blkbits; | |
489 | + int ret = 0; | |
484 | 490 | |
485 | 491 | mutex_lock(&inode->i_mutex); |
486 | - if (offset >= inode->i_size) { | |
492 | + | |
493 | + isize = i_size_read(inode); | |
494 | + if (offset >= isize) { | |
487 | 495 | mutex_unlock(&inode->i_mutex); |
488 | 496 | return -ENXIO; |
489 | 497 | } |
490 | 498 | |
491 | - fie.fi_flags = 0; | |
492 | - fie.fi_extents_max = 2; | |
493 | - fie.fi_extents_start = (struct fiemap_extent __user *)&ext; | |
494 | - while (1) { | |
495 | - mm_segment_t old_fs = get_fs(); | |
499 | + blkbits = inode->i_sb->s_blocksize_bits; | |
500 | + start = offset >> blkbits; | |
501 | + last = start; | |
502 | + end = isize >> blkbits; | |
503 | + holeoff = offset; | |
496 | 504 | |
497 | - fie.fi_extents_mapped = 0; | |
498 | - memset(ext, 0, sizeof(*ext)); | |
505 | + do { | |
506 | + map.m_lblk = last; | |
507 | + map.m_len = end - last + 1; | |
508 | + ret = ext4_map_blocks(NULL, inode, &map, 0); | |
509 | + if (ret > 0 && !(map.m_flags & EXT4_MAP_UNWRITTEN)) { | |
510 | + last += ret; | |
511 | + holeoff = (loff_t)last << blkbits; | |
512 | + continue; | |
513 | + } | |
499 | 514 | |
500 | - set_fs(get_ds()); | |
501 | - ret = ext4_fiemap(inode, &fie, offset, maxsize - offset); | |
502 | - set_fs(old_fs); | |
503 | - if (ret) | |
504 | - break; | |
515 | + /* | |
516 | + * If there is a delay extent at this offset, | |
517 | + * we will skip this extent. | |
518 | + */ | |
519 | + ext4_es_find_delayed_extent_range(inode, last, last, &es); | |
520 | + if (es.es_len != 0 && in_range(last, es.es_lblk, es.es_len)) { | |
521 | + last = es.es_lblk + es.es_len; | |
522 | + holeoff = (loff_t)last << blkbits; | |
523 | + continue; | |
524 | + } | |
505 | 525 | |
506 | - /* No extents found */ | |
507 | - if (!fie.fi_extents_mapped) | |
508 | - break; | |
509 | - | |
510 | - for (i = 0; i < fie.fi_extents_mapped; i++) { | |
511 | - next = (loff_t)(ext[i].fe_logical + ext[i].fe_length); | |
512 | - /* | |
513 | - * If extent is not unwritten, then it contains valid | |
514 | - * data, mapped or delayed. | |
515 | - */ | |
516 | - if (!(ext[i].fe_flags & FIEMAP_EXTENT_UNWRITTEN)) { | |
517 | - if (offset < (loff_t)ext[i].fe_logical) | |
518 | - goto out; | |
519 | - offset = next; | |
526 | + /* | |
527 | + * If there is a unwritten extent at this offset, | |
528 | + * it will be as a data or a hole according to page | |
529 | + * cache that has data or not. | |
530 | + */ | |
531 | + if (map.m_flags & EXT4_MAP_UNWRITTEN) { | |
532 | + int unwritten; | |
533 | + unwritten = ext4_find_unwritten_pgoff(inode, SEEK_HOLE, | |
534 | + &map, &holeoff); | |
535 | + if (!unwritten) { | |
536 | + last += ret; | |
537 | + holeoff = (loff_t)last << blkbits; | |
520 | 538 | continue; |
521 | 539 | } |
522 | - /* | |
523 | - * If there is a unwritten extent at this offset, | |
524 | - * it will be as a data or a hole according to page | |
525 | - * cache that has data or not. | |
526 | - */ | |
527 | - if (ext4_find_unwritten_pgoff(inode, SEEK_HOLE, | |
528 | - next, &offset)) | |
529 | - goto out; | |
530 | - | |
531 | - offset = next; | |
532 | - if (ext[i].fe_flags & FIEMAP_EXTENT_LAST) | |
533 | - goto out; | |
534 | 540 | } |
535 | - } | |
536 | - if (offset > inode->i_size) | |
537 | - offset = inode->i_size; | |
538 | -out: | |
541 | + | |
542 | + /* find a hole */ | |
543 | + break; | |
544 | + } while (last <= end); | |
545 | + | |
539 | 546 | mutex_unlock(&inode->i_mutex); |
540 | - if (ret) | |
541 | - return ret; | |
542 | 547 | |
543 | - return vfs_setpos(file, offset, maxsize); | |
548 | + if (holeoff > isize) | |
549 | + holeoff = isize; | |
550 | + | |
551 | + return vfs_setpos(file, holeoff, maxsize); | |
544 | 552 | } |
545 | 553 | |
546 | 554 | /* |