diff options
-rw-r--r-- | fs/btrfs/extent-tree.c | 1 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 12 | ||||
-rw-r--r-- | fs/btrfs/file.c | 47 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 120 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 3 |
5 files changed, 168 insertions, 15 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 76fd5d7146e1..593011e5d455 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -1747,6 +1747,7 @@ again: | |||
1747 | search_start, search_end, hint_byte, ins, | 1747 | search_start, search_end, hint_byte, ins, |
1748 | trans->alloc_exclude_start, | 1748 | trans->alloc_exclude_start, |
1749 | trans->alloc_exclude_nr, data); | 1749 | trans->alloc_exclude_nr, data); |
1750 | |||
1750 | if (ret == -ENOSPC && num_bytes > min_alloc_size) { | 1751 | if (ret == -ENOSPC && num_bytes > min_alloc_size) { |
1751 | num_bytes = num_bytes >> 1; | 1752 | num_bytes = num_bytes >> 1; |
1752 | num_bytes = max(num_bytes, min_alloc_size); | 1753 | num_bytes = max(num_bytes, min_alloc_size); |
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 88322684be6a..21597bea21fd 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -1025,7 +1025,8 @@ u64 find_lock_delalloc_range(struct extent_io_tree *tree, | |||
1025 | search_again: | 1025 | search_again: |
1026 | node = tree_search(tree, cur_start); | 1026 | node = tree_search(tree, cur_start); |
1027 | if (!node) { | 1027 | if (!node) { |
1028 | *end = (u64)-1; | 1028 | if (!found) |
1029 | *end = (u64)-1; | ||
1029 | goto out; | 1030 | goto out; |
1030 | } | 1031 | } |
1031 | 1032 | ||
@@ -1540,6 +1541,8 @@ static int end_bio_extent_readpage(struct bio *bio, | |||
1540 | start, end, state); | 1541 | start, end, state); |
1541 | if (ret == 0) { | 1542 | if (ret == 0) { |
1542 | state = NULL; | 1543 | state = NULL; |
1544 | uptodate = | ||
1545 | test_bit(BIO_UPTODATE, &bio->bi_flags); | ||
1543 | continue; | 1546 | continue; |
1544 | } | 1547 | } |
1545 | } | 1548 | } |
@@ -1555,10 +1558,11 @@ static int end_bio_extent_readpage(struct bio *bio, | |||
1555 | !(state->state & EXTENT_LOCKED)) | 1558 | !(state->state & EXTENT_LOCKED)) |
1556 | state = NULL; | 1559 | state = NULL; |
1557 | } | 1560 | } |
1558 | if (!state && uptodate) { | 1561 | if (!state) { |
1559 | spin_unlock_irqrestore(&tree->lock, flags); | 1562 | spin_unlock_irqrestore(&tree->lock, flags); |
1560 | set_extent_uptodate(tree, start, end, | 1563 | if (uptodate) |
1561 | GFP_ATOMIC); | 1564 | set_extent_uptodate(tree, start, end, |
1565 | GFP_ATOMIC); | ||
1562 | unlock_extent(tree, start, end, GFP_ATOMIC); | 1566 | unlock_extent(tree, start, end, GFP_ATOMIC); |
1563 | goto next_io; | 1567 | goto next_io; |
1564 | } | 1568 | } |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 9fbda6552069..3f5525f0834c 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -356,12 +356,23 @@ out_unlock: | |||
356 | int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | 356 | int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) |
357 | { | 357 | { |
358 | struct extent_map *em; | 358 | struct extent_map *em; |
359 | struct extent_map *split = NULL; | ||
360 | struct extent_map *split2 = NULL; | ||
359 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | 361 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
360 | u64 len = end - start + 1; | 362 | u64 len = end - start + 1; |
363 | int ret; | ||
364 | int testend = 1; | ||
361 | 365 | ||
362 | if (end == (u64)-1) | 366 | if (end == (u64)-1) { |
363 | len = (u64)-1; | 367 | len = (u64)-1; |
368 | testend = 0; | ||
369 | } | ||
364 | while(1) { | 370 | while(1) { |
371 | if (!split) | ||
372 | split = alloc_extent_map(GFP_NOFS); | ||
373 | if (!split2) | ||
374 | split2 = alloc_extent_map(GFP_NOFS); | ||
375 | |||
365 | spin_lock(&em_tree->lock); | 376 | spin_lock(&em_tree->lock); |
366 | em = lookup_extent_mapping(em_tree, start, len); | 377 | em = lookup_extent_mapping(em_tree, start, len); |
367 | if (!em) { | 378 | if (!em) { |
@@ -369,6 +380,36 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | |||
369 | break; | 380 | break; |
370 | } | 381 | } |
371 | remove_extent_mapping(em_tree, em); | 382 | remove_extent_mapping(em_tree, em); |
383 | |||
384 | if (em->block_start < EXTENT_MAP_LAST_BYTE && | ||
385 | em->start < start) { | ||
386 | split->start = em->start; | ||
387 | split->len = start - em->start; | ||
388 | split->block_start = em->block_start; | ||
389 | split->bdev = em->bdev; | ||
390 | split->flags = em->flags; | ||
391 | ret = add_extent_mapping(em_tree, split); | ||
392 | BUG_ON(ret); | ||
393 | free_extent_map(split); | ||
394 | split = split2; | ||
395 | split2 = NULL; | ||
396 | } | ||
397 | if (em->block_start < EXTENT_MAP_LAST_BYTE && | ||
398 | testend && em->start + em->len > start + len) { | ||
399 | u64 diff = start + len - em->start; | ||
400 | |||
401 | split->start = start + len; | ||
402 | split->len = em->start + em->len - (start + len); | ||
403 | split->bdev = em->bdev; | ||
404 | split->flags = em->flags; | ||
405 | |||
406 | split->block_start = em->block_start + diff; | ||
407 | |||
408 | ret = add_extent_mapping(em_tree, split); | ||
409 | BUG_ON(ret); | ||
410 | free_extent_map(split); | ||
411 | split = NULL; | ||
412 | } | ||
372 | spin_unlock(&em_tree->lock); | 413 | spin_unlock(&em_tree->lock); |
373 | 414 | ||
374 | /* once for us */ | 415 | /* once for us */ |
@@ -376,6 +417,10 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | |||
376 | /* once for the tree*/ | 417 | /* once for the tree*/ |
377 | free_extent_map(em); | 418 | free_extent_map(em); |
378 | } | 419 | } |
420 | if (split) | ||
421 | free_extent_map(split); | ||
422 | if (split2) | ||
423 | free_extent_map(split2); | ||
379 | return 0; | 424 | return 0; |
380 | } | 425 | } |
381 | 426 | ||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5632ea760077..40f8da884090 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -122,6 +122,8 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end) | |||
122 | if (alloc_hint == EXTENT_MAP_INLINE) | 122 | if (alloc_hint == EXTENT_MAP_INLINE) |
123 | goto out; | 123 | goto out; |
124 | 124 | ||
125 | BUG_ON(num_bytes > btrfs_super_total_bytes(&root->fs_info->super_copy)); | ||
126 | |||
125 | while(num_bytes > 0) { | 127 | while(num_bytes > 0) { |
126 | cur_alloc_size = min(num_bytes, root->fs_info->max_extent); | 128 | cur_alloc_size = min(num_bytes, root->fs_info->max_extent); |
127 | ret = btrfs_alloc_extent(trans, root, cur_alloc_size, | 129 | ret = btrfs_alloc_extent(trans, root, cur_alloc_size, |
@@ -140,6 +142,11 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end) | |||
140 | ins.offset); | 142 | ins.offset); |
141 | inode->i_blocks += ins.offset >> 9; | 143 | inode->i_blocks += ins.offset >> 9; |
142 | btrfs_check_file(root, inode); | 144 | btrfs_check_file(root, inode); |
145 | if (num_bytes < cur_alloc_size) { | ||
146 | printk("num_bytes %Lu cur_alloc %Lu\n", num_bytes, | ||
147 | cur_alloc_size); | ||
148 | break; | ||
149 | } | ||
143 | num_bytes -= cur_alloc_size; | 150 | num_bytes -= cur_alloc_size; |
144 | alloc_hint = ins.objectid + ins.offset; | 151 | alloc_hint = ins.objectid + ins.offset; |
145 | start += cur_alloc_size; | 152 | start += cur_alloc_size; |
@@ -427,6 +434,7 @@ int btrfs_readpage_io_failed_hook(struct bio *failed_bio, | |||
427 | struct extent_map *em; | 434 | struct extent_map *em; |
428 | struct inode *inode = page->mapping->host; | 435 | struct inode *inode = page->mapping->host; |
429 | struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree; | 436 | struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree; |
437 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | ||
430 | struct bio *bio; | 438 | struct bio *bio; |
431 | int num_copies; | 439 | int num_copies; |
432 | int ret; | 440 | int ret; |
@@ -434,7 +442,6 @@ int btrfs_readpage_io_failed_hook(struct bio *failed_bio, | |||
434 | 442 | ||
435 | ret = get_state_private(failure_tree, start, &private); | 443 | ret = get_state_private(failure_tree, start, &private); |
436 | if (ret) { | 444 | if (ret) { |
437 | size_t pg_offset = start - page_offset(page); | ||
438 | failrec = kmalloc(sizeof(*failrec), GFP_NOFS); | 445 | failrec = kmalloc(sizeof(*failrec), GFP_NOFS); |
439 | if (!failrec) | 446 | if (!failrec) |
440 | return -ENOMEM; | 447 | return -ENOMEM; |
@@ -442,8 +449,13 @@ int btrfs_readpage_io_failed_hook(struct bio *failed_bio, | |||
442 | failrec->len = end - start + 1; | 449 | failrec->len = end - start + 1; |
443 | failrec->last_mirror = 0; | 450 | failrec->last_mirror = 0; |
444 | 451 | ||
445 | em = btrfs_get_extent(inode, NULL, pg_offset, start, | 452 | spin_lock(&em_tree->lock); |
446 | failrec->len, 0); | 453 | em = lookup_extent_mapping(em_tree, start, failrec->len); |
454 | if (em->start > start || em->start + em->len < start) { | ||
455 | free_extent_map(em); | ||
456 | em = NULL; | ||
457 | } | ||
458 | spin_unlock(&em_tree->lock); | ||
447 | 459 | ||
448 | if (!em || IS_ERR(em)) { | 460 | if (!em || IS_ERR(em)) { |
449 | kfree(failrec); | 461 | kfree(failrec); |
@@ -559,6 +571,8 @@ zeroit: | |||
559 | flush_dcache_page(page); | 571 | flush_dcache_page(page); |
560 | kunmap_atomic(kaddr, KM_IRQ0); | 572 | kunmap_atomic(kaddr, KM_IRQ0); |
561 | local_irq_restore(flags); | 573 | local_irq_restore(flags); |
574 | if (private == 0) | ||
575 | return 0; | ||
562 | return -EIO; | 576 | return -EIO; |
563 | } | 577 | } |
564 | 578 | ||
@@ -908,8 +922,9 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
908 | int pending_del_nr = 0; | 922 | int pending_del_nr = 0; |
909 | int pending_del_slot = 0; | 923 | int pending_del_slot = 0; |
910 | int extent_type = -1; | 924 | int extent_type = -1; |
925 | u64 mask = root->sectorsize - 1; | ||
911 | 926 | ||
912 | btrfs_drop_extent_cache(inode, inode->i_size, (u64)-1); | 927 | btrfs_drop_extent_cache(inode, inode->i_size & (~mask), (u64)-1); |
913 | path = btrfs_alloc_path(); | 928 | path = btrfs_alloc_path(); |
914 | path->reada = -1; | 929 | path->reada = -1; |
915 | BUG_ON(!path); | 930 | BUG_ON(!path); |
@@ -1212,7 +1227,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
1212 | hole_start, 0, 0, | 1227 | hole_start, 0, 0, |
1213 | hole_size); | 1228 | hole_size); |
1214 | btrfs_drop_extent_cache(inode, hole_start, | 1229 | btrfs_drop_extent_cache(inode, hole_start, |
1215 | hole_size - 1); | 1230 | (u64)-1); |
1216 | btrfs_check_file(root, inode); | 1231 | btrfs_check_file(root, inode); |
1217 | } | 1232 | } |
1218 | btrfs_end_transaction(trans, root); | 1233 | btrfs_end_transaction(trans, root); |
@@ -2083,6 +2098,68 @@ out_unlock: | |||
2083 | return err; | 2098 | return err; |
2084 | } | 2099 | } |
2085 | 2100 | ||
2101 | static int merge_extent_mapping(struct extent_map_tree *em_tree, | ||
2102 | struct extent_map *existing, | ||
2103 | struct extent_map *em) | ||
2104 | { | ||
2105 | u64 start_diff; | ||
2106 | u64 new_end; | ||
2107 | int ret = 0; | ||
2108 | int real_blocks = existing->block_start < EXTENT_MAP_LAST_BYTE; | ||
2109 | |||
2110 | if (real_blocks && em->block_start >= EXTENT_MAP_LAST_BYTE) | ||
2111 | goto invalid; | ||
2112 | |||
2113 | if (!real_blocks && em->block_start != existing->block_start) | ||
2114 | goto invalid; | ||
2115 | |||
2116 | new_end = max(existing->start + existing->len, em->start + em->len); | ||
2117 | |||
2118 | if (existing->start >= em->start) { | ||
2119 | if (em->start + em->len < existing->start) | ||
2120 | goto invalid; | ||
2121 | |||
2122 | start_diff = existing->start - em->start; | ||
2123 | if (real_blocks && em->block_start + start_diff != | ||
2124 | existing->block_start) | ||
2125 | goto invalid; | ||
2126 | |||
2127 | em->len = new_end - em->start; | ||
2128 | |||
2129 | remove_extent_mapping(em_tree, existing); | ||
2130 | /* free for the tree */ | ||
2131 | free_extent_map(existing); | ||
2132 | ret = add_extent_mapping(em_tree, em); | ||
2133 | |||
2134 | } else if (em->start > existing->start) { | ||
2135 | |||
2136 | if (existing->start + existing->len < em->start) | ||
2137 | goto invalid; | ||
2138 | |||
2139 | start_diff = em->start - existing->start; | ||
2140 | if (real_blocks && existing->block_start + start_diff != | ||
2141 | em->block_start) | ||
2142 | goto invalid; | ||
2143 | |||
2144 | remove_extent_mapping(em_tree, existing); | ||
2145 | em->block_start = existing->block_start; | ||
2146 | em->start = existing->start; | ||
2147 | em->len = new_end - existing->start; | ||
2148 | free_extent_map(existing); | ||
2149 | |||
2150 | ret = add_extent_mapping(em_tree, em); | ||
2151 | } else { | ||
2152 | goto invalid; | ||
2153 | } | ||
2154 | return ret; | ||
2155 | |||
2156 | invalid: | ||
2157 | printk("invalid extent map merge [%Lu %Lu %Lu] [%Lu %Lu %Lu]\n", | ||
2158 | existing->start, existing->len, existing->block_start, | ||
2159 | em->start, em->len, em->block_start); | ||
2160 | return -EIO; | ||
2161 | } | ||
2162 | |||
2086 | struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, | 2163 | struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, |
2087 | size_t pg_offset, u64 start, u64 len, | 2164 | size_t pg_offset, u64 start, u64 len, |
2088 | int create) | 2165 | int create) |
@@ -2267,12 +2344,35 @@ insert: | |||
2267 | err = 0; | 2344 | err = 0; |
2268 | spin_lock(&em_tree->lock); | 2345 | spin_lock(&em_tree->lock); |
2269 | ret = add_extent_mapping(em_tree, em); | 2346 | ret = add_extent_mapping(em_tree, em); |
2347 | |||
2348 | /* it is possible that someone inserted the extent into the tree | ||
2349 | * while we had the lock dropped. It is also possible that | ||
2350 | * an overlapping map exists in the tree | ||
2351 | */ | ||
2270 | if (ret == -EEXIST) { | 2352 | if (ret == -EEXIST) { |
2271 | free_extent_map(em); | 2353 | struct extent_map *existing; |
2272 | em = lookup_extent_mapping(em_tree, start, len); | 2354 | existing = lookup_extent_mapping(em_tree, start, len); |
2273 | if (!em) { | 2355 | if (!existing) { |
2274 | err = -EIO; | 2356 | existing = lookup_extent_mapping(em_tree, em->start, |
2275 | printk("failing to insert %Lu %Lu\n", start, len); | 2357 | em->len); |
2358 | if (existing) { | ||
2359 | err = merge_extent_mapping(em_tree, existing, | ||
2360 | em); | ||
2361 | free_extent_map(existing); | ||
2362 | if (err) { | ||
2363 | free_extent_map(em); | ||
2364 | em = NULL; | ||
2365 | } | ||
2366 | } else { | ||
2367 | err = -EIO; | ||
2368 | printk("failing to insert %Lu %Lu\n", | ||
2369 | start, len); | ||
2370 | free_extent_map(em); | ||
2371 | em = NULL; | ||
2372 | } | ||
2373 | } else { | ||
2374 | free_extent_map(em); | ||
2375 | em = existing; | ||
2276 | } | 2376 | } |
2277 | } | 2377 | } |
2278 | spin_unlock(&em_tree->lock); | 2378 | spin_unlock(&em_tree->lock); |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index e6417a573d44..0e658c1d8211 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -883,6 +883,9 @@ again: | |||
883 | spin_lock(&em_tree->lock); | 883 | spin_lock(&em_tree->lock); |
884 | em = lookup_extent_mapping(em_tree, logical, *length); | 884 | em = lookup_extent_mapping(em_tree, logical, *length); |
885 | spin_unlock(&em_tree->lock); | 885 | spin_unlock(&em_tree->lock); |
886 | if (!em) { | ||
887 | printk("unable to find logical %Lu\n", logical); | ||
888 | } | ||
886 | BUG_ON(!em); | 889 | BUG_ON(!em); |
887 | 890 | ||
888 | BUG_ON(em->start > logical || em->start + em->len < logical); | 891 | BUG_ON(em->start > logical || em->start + em->len < logical); |