diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/file.c | 94 |
1 files changed, 19 insertions, 75 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 72da4df53c9a..bf3465cf455a 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -2405,14 +2405,12 @@ out_reserve_fail: | |||
2405 | static int find_desired_extent(struct inode *inode, loff_t *offset, int whence) | 2405 | static int find_desired_extent(struct inode *inode, loff_t *offset, int whence) |
2406 | { | 2406 | { |
2407 | struct btrfs_root *root = BTRFS_I(inode)->root; | 2407 | struct btrfs_root *root = BTRFS_I(inode)->root; |
2408 | struct extent_map *em; | 2408 | struct extent_map *em = NULL; |
2409 | struct extent_state *cached_state = NULL; | 2409 | struct extent_state *cached_state = NULL; |
2410 | u64 lockstart = *offset; | 2410 | u64 lockstart = *offset; |
2411 | u64 lockend = i_size_read(inode); | 2411 | u64 lockend = i_size_read(inode); |
2412 | u64 start = *offset; | 2412 | u64 start = *offset; |
2413 | u64 orig_start = *offset; | ||
2414 | u64 len = i_size_read(inode); | 2413 | u64 len = i_size_read(inode); |
2415 | u64 last_end = 0; | ||
2416 | int ret = 0; | 2414 | int ret = 0; |
2417 | 2415 | ||
2418 | lockend = max_t(u64, root->sectorsize, lockend); | 2416 | lockend = max_t(u64, root->sectorsize, lockend); |
@@ -2429,89 +2427,35 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence) | |||
2429 | lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, 0, | 2427 | lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, 0, |
2430 | &cached_state); | 2428 | &cached_state); |
2431 | 2429 | ||
2432 | /* | 2430 | while (start < inode->i_size) { |
2433 | * Delalloc is such a pain. If we have a hole and we have pending | ||
2434 | * delalloc for a portion of the hole we will get back a hole that | ||
2435 | * exists for the entire range since it hasn't been actually written | ||
2436 | * yet. So to take care of this case we need to look for an extent just | ||
2437 | * before the position we want in case there is outstanding delalloc | ||
2438 | * going on here. | ||
2439 | */ | ||
2440 | if (whence == SEEK_HOLE && start != 0) { | ||
2441 | if (start <= root->sectorsize) | ||
2442 | em = btrfs_get_extent_fiemap(inode, NULL, 0, 0, | ||
2443 | root->sectorsize, 0); | ||
2444 | else | ||
2445 | em = btrfs_get_extent_fiemap(inode, NULL, 0, | ||
2446 | start - root->sectorsize, | ||
2447 | root->sectorsize, 0); | ||
2448 | if (IS_ERR(em)) { | ||
2449 | ret = PTR_ERR(em); | ||
2450 | goto out; | ||
2451 | } | ||
2452 | last_end = em->start + em->len; | ||
2453 | if (em->block_start == EXTENT_MAP_DELALLOC) | ||
2454 | last_end = min_t(u64, last_end, inode->i_size); | ||
2455 | free_extent_map(em); | ||
2456 | } | ||
2457 | |||
2458 | while (1) { | ||
2459 | em = btrfs_get_extent_fiemap(inode, NULL, 0, start, len, 0); | 2431 | em = btrfs_get_extent_fiemap(inode, NULL, 0, start, len, 0); |
2460 | if (IS_ERR(em)) { | 2432 | if (IS_ERR(em)) { |
2461 | ret = PTR_ERR(em); | 2433 | ret = PTR_ERR(em); |
2434 | em = NULL; | ||
2462 | break; | 2435 | break; |
2463 | } | 2436 | } |
2464 | 2437 | ||
2465 | if (em->block_start == EXTENT_MAP_HOLE) { | 2438 | if (whence == SEEK_HOLE && |
2466 | if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) { | 2439 | (em->block_start == EXTENT_MAP_HOLE || |
2467 | if (last_end <= orig_start) { | 2440 | test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) |
2468 | free_extent_map(em); | 2441 | break; |
2469 | ret = -ENXIO; | 2442 | else if (whence == SEEK_DATA && |
2470 | break; | 2443 | (em->block_start != EXTENT_MAP_HOLE && |
2471 | } | 2444 | !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) |
2472 | } | 2445 | break; |
2473 | |||
2474 | if (whence == SEEK_HOLE) { | ||
2475 | *offset = start; | ||
2476 | free_extent_map(em); | ||
2477 | break; | ||
2478 | } | ||
2479 | } else { | ||
2480 | if (whence == SEEK_DATA) { | ||
2481 | if (em->block_start == EXTENT_MAP_DELALLOC) { | ||
2482 | if (start >= inode->i_size) { | ||
2483 | free_extent_map(em); | ||
2484 | ret = -ENXIO; | ||
2485 | break; | ||
2486 | } | ||
2487 | } | ||
2488 | |||
2489 | if (!test_bit(EXTENT_FLAG_PREALLOC, | ||
2490 | &em->flags)) { | ||
2491 | *offset = start; | ||
2492 | free_extent_map(em); | ||
2493 | break; | ||
2494 | } | ||
2495 | } | ||
2496 | } | ||
2497 | 2446 | ||
2498 | start = em->start + em->len; | 2447 | start = em->start + em->len; |
2499 | last_end = em->start + em->len; | ||
2500 | |||
2501 | if (em->block_start == EXTENT_MAP_DELALLOC) | ||
2502 | last_end = min_t(u64, last_end, inode->i_size); | ||
2503 | |||
2504 | if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) { | ||
2505 | free_extent_map(em); | ||
2506 | ret = -ENXIO; | ||
2507 | break; | ||
2508 | } | ||
2509 | free_extent_map(em); | 2448 | free_extent_map(em); |
2449 | em = NULL; | ||
2510 | cond_resched(); | 2450 | cond_resched(); |
2511 | } | 2451 | } |
2512 | if (!ret) | 2452 | free_extent_map(em); |
2513 | *offset = min(*offset, inode->i_size); | 2453 | if (!ret) { |
2514 | out: | 2454 | if (whence == SEEK_DATA && start >= inode->i_size) |
2455 | ret = -ENXIO; | ||
2456 | else | ||
2457 | *offset = min_t(loff_t, start, inode->i_size); | ||
2458 | } | ||
2515 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, | 2459 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, |
2516 | &cached_state, GFP_NOFS); | 2460 | &cached_state, GFP_NOFS); |
2517 | return ret; | 2461 | return ret; |