diff options
-rw-r--r-- | fs/btrfs/ctree.c | 28 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 18 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 3 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 2 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 4 | ||||
-rw-r--r-- | fs/btrfs/ioctl.h | 4 | ||||
-rw-r--r-- | fs/btrfs/scrub.c | 7 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 2 |
8 files changed, 47 insertions, 21 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index e801f226d7e0..4106264fbc65 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -220,10 +220,12 @@ struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root) | |||
220 | */ | 220 | */ |
221 | static void add_root_to_dirty_list(struct btrfs_root *root) | 221 | static void add_root_to_dirty_list(struct btrfs_root *root) |
222 | { | 222 | { |
223 | spin_lock(&root->fs_info->trans_lock); | ||
223 | if (root->track_dirty && list_empty(&root->dirty_list)) { | 224 | if (root->track_dirty && list_empty(&root->dirty_list)) { |
224 | list_add(&root->dirty_list, | 225 | list_add(&root->dirty_list, |
225 | &root->fs_info->dirty_cowonly_roots); | 226 | &root->fs_info->dirty_cowonly_roots); |
226 | } | 227 | } |
228 | spin_unlock(&root->fs_info->trans_lock); | ||
227 | } | 229 | } |
228 | 230 | ||
229 | /* | 231 | /* |
@@ -723,7 +725,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, | |||
723 | 725 | ||
724 | cur = btrfs_find_tree_block(root, blocknr, blocksize); | 726 | cur = btrfs_find_tree_block(root, blocknr, blocksize); |
725 | if (cur) | 727 | if (cur) |
726 | uptodate = btrfs_buffer_uptodate(cur, gen); | 728 | uptodate = btrfs_buffer_uptodate(cur, gen, 0); |
727 | else | 729 | else |
728 | uptodate = 0; | 730 | uptodate = 0; |
729 | if (!cur || !uptodate) { | 731 | if (!cur || !uptodate) { |
@@ -1358,7 +1360,12 @@ static noinline int reada_for_balance(struct btrfs_root *root, | |||
1358 | block1 = btrfs_node_blockptr(parent, slot - 1); | 1360 | block1 = btrfs_node_blockptr(parent, slot - 1); |
1359 | gen = btrfs_node_ptr_generation(parent, slot - 1); | 1361 | gen = btrfs_node_ptr_generation(parent, slot - 1); |
1360 | eb = btrfs_find_tree_block(root, block1, blocksize); | 1362 | eb = btrfs_find_tree_block(root, block1, blocksize); |
1361 | if (eb && btrfs_buffer_uptodate(eb, gen)) | 1363 | /* |
1364 | * if we get -eagain from btrfs_buffer_uptodate, we | ||
1365 | * don't want to return eagain here. That will loop | ||
1366 | * forever | ||
1367 | */ | ||
1368 | if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0) | ||
1362 | block1 = 0; | 1369 | block1 = 0; |
1363 | free_extent_buffer(eb); | 1370 | free_extent_buffer(eb); |
1364 | } | 1371 | } |
@@ -1366,7 +1373,7 @@ static noinline int reada_for_balance(struct btrfs_root *root, | |||
1366 | block2 = btrfs_node_blockptr(parent, slot + 1); | 1373 | block2 = btrfs_node_blockptr(parent, slot + 1); |
1367 | gen = btrfs_node_ptr_generation(parent, slot + 1); | 1374 | gen = btrfs_node_ptr_generation(parent, slot + 1); |
1368 | eb = btrfs_find_tree_block(root, block2, blocksize); | 1375 | eb = btrfs_find_tree_block(root, block2, blocksize); |
1369 | if (eb && btrfs_buffer_uptodate(eb, gen)) | 1376 | if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0) |
1370 | block2 = 0; | 1377 | block2 = 0; |
1371 | free_extent_buffer(eb); | 1378 | free_extent_buffer(eb); |
1372 | } | 1379 | } |
@@ -1504,8 +1511,9 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
1504 | 1511 | ||
1505 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); | 1512 | tmp = btrfs_find_tree_block(root, blocknr, blocksize); |
1506 | if (tmp) { | 1513 | if (tmp) { |
1507 | if (btrfs_buffer_uptodate(tmp, 0)) { | 1514 | /* first we do an atomic uptodate check */ |
1508 | if (btrfs_buffer_uptodate(tmp, gen)) { | 1515 | if (btrfs_buffer_uptodate(tmp, 0, 1) > 0) { |
1516 | if (btrfs_buffer_uptodate(tmp, gen, 1) > 0) { | ||
1509 | /* | 1517 | /* |
1510 | * we found an up to date block without | 1518 | * we found an up to date block without |
1511 | * sleeping, return | 1519 | * sleeping, return |
@@ -1523,8 +1531,9 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
1523 | free_extent_buffer(tmp); | 1531 | free_extent_buffer(tmp); |
1524 | btrfs_set_path_blocking(p); | 1532 | btrfs_set_path_blocking(p); |
1525 | 1533 | ||
1534 | /* now we're allowed to do a blocking uptodate check */ | ||
1526 | tmp = read_tree_block(root, blocknr, blocksize, gen); | 1535 | tmp = read_tree_block(root, blocknr, blocksize, gen); |
1527 | if (tmp && btrfs_buffer_uptodate(tmp, gen)) { | 1536 | if (tmp && btrfs_buffer_uptodate(tmp, gen, 0) > 0) { |
1528 | *eb_ret = tmp; | 1537 | *eb_ret = tmp; |
1529 | return 0; | 1538 | return 0; |
1530 | } | 1539 | } |
@@ -1559,7 +1568,7 @@ read_block_for_search(struct btrfs_trans_handle *trans, | |||
1559 | * and give up so that our caller doesn't loop forever | 1568 | * and give up so that our caller doesn't loop forever |
1560 | * on our EAGAINs. | 1569 | * on our EAGAINs. |
1561 | */ | 1570 | */ |
1562 | if (!btrfs_buffer_uptodate(tmp, 0)) | 1571 | if (!btrfs_buffer_uptodate(tmp, 0, 0)) |
1563 | ret = -EIO; | 1572 | ret = -EIO; |
1564 | free_extent_buffer(tmp); | 1573 | free_extent_buffer(tmp); |
1565 | } | 1574 | } |
@@ -4043,7 +4052,7 @@ again: | |||
4043 | tmp = btrfs_find_tree_block(root, blockptr, | 4052 | tmp = btrfs_find_tree_block(root, blockptr, |
4044 | btrfs_level_size(root, level - 1)); | 4053 | btrfs_level_size(root, level - 1)); |
4045 | 4054 | ||
4046 | if (tmp && btrfs_buffer_uptodate(tmp, gen)) { | 4055 | if (tmp && btrfs_buffer_uptodate(tmp, gen, 1) > 0) { |
4047 | free_extent_buffer(tmp); | 4056 | free_extent_buffer(tmp); |
4048 | break; | 4057 | break; |
4049 | } | 4058 | } |
@@ -4166,7 +4175,8 @@ next: | |||
4166 | struct extent_buffer *cur; | 4175 | struct extent_buffer *cur; |
4167 | cur = btrfs_find_tree_block(root, blockptr, | 4176 | cur = btrfs_find_tree_block(root, blockptr, |
4168 | btrfs_level_size(root, level - 1)); | 4177 | btrfs_level_size(root, level - 1)); |
4169 | if (!cur || !btrfs_buffer_uptodate(cur, gen)) { | 4178 | if (!cur || |
4179 | btrfs_buffer_uptodate(cur, gen, 1) <= 0) { | ||
4170 | slot++; | 4180 | slot++; |
4171 | if (cur) | 4181 | if (cur) |
4172 | free_extent_buffer(cur); | 4182 | free_extent_buffer(cur); |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index d0c969beaad4..a7ffc88a7dbe 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -323,7 +323,8 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, | |||
323 | * in the wrong place. | 323 | * in the wrong place. |
324 | */ | 324 | */ |
325 | static int verify_parent_transid(struct extent_io_tree *io_tree, | 325 | static int verify_parent_transid(struct extent_io_tree *io_tree, |
326 | struct extent_buffer *eb, u64 parent_transid) | 326 | struct extent_buffer *eb, u64 parent_transid, |
327 | int atomic) | ||
327 | { | 328 | { |
328 | struct extent_state *cached_state = NULL; | 329 | struct extent_state *cached_state = NULL; |
329 | int ret; | 330 | int ret; |
@@ -331,6 +332,9 @@ static int verify_parent_transid(struct extent_io_tree *io_tree, | |||
331 | if (!parent_transid || btrfs_header_generation(eb) == parent_transid) | 332 | if (!parent_transid || btrfs_header_generation(eb) == parent_transid) |
332 | return 0; | 333 | return 0; |
333 | 334 | ||
335 | if (atomic) | ||
336 | return -EAGAIN; | ||
337 | |||
334 | lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1, | 338 | lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1, |
335 | 0, &cached_state); | 339 | 0, &cached_state); |
336 | if (extent_buffer_uptodate(eb) && | 340 | if (extent_buffer_uptodate(eb) && |
@@ -372,7 +376,8 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, | |||
372 | ret = read_extent_buffer_pages(io_tree, eb, start, | 376 | ret = read_extent_buffer_pages(io_tree, eb, start, |
373 | WAIT_COMPLETE, | 377 | WAIT_COMPLETE, |
374 | btree_get_extent, mirror_num); | 378 | btree_get_extent, mirror_num); |
375 | if (!ret && !verify_parent_transid(io_tree, eb, parent_transid)) | 379 | if (!ret && !verify_parent_transid(io_tree, eb, |
380 | parent_transid, 0)) | ||
376 | break; | 381 | break; |
377 | 382 | ||
378 | /* | 383 | /* |
@@ -1202,7 +1207,7 @@ static int __must_check find_and_setup_root(struct btrfs_root *tree_root, | |||
1202 | root->commit_root = NULL; | 1207 | root->commit_root = NULL; |
1203 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), | 1208 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), |
1204 | blocksize, generation); | 1209 | blocksize, generation); |
1205 | if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) { | 1210 | if (!root->node || !btrfs_buffer_uptodate(root->node, generation, 0)) { |
1206 | free_extent_buffer(root->node); | 1211 | free_extent_buffer(root->node); |
1207 | root->node = NULL; | 1212 | root->node = NULL; |
1208 | return -EIO; | 1213 | return -EIO; |
@@ -3143,7 +3148,8 @@ int close_ctree(struct btrfs_root *root) | |||
3143 | return 0; | 3148 | return 0; |
3144 | } | 3149 | } |
3145 | 3150 | ||
3146 | int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid) | 3151 | int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, |
3152 | int atomic) | ||
3147 | { | 3153 | { |
3148 | int ret; | 3154 | int ret; |
3149 | struct inode *btree_inode = buf->pages[0]->mapping->host; | 3155 | struct inode *btree_inode = buf->pages[0]->mapping->host; |
@@ -3153,7 +3159,9 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid) | |||
3153 | return ret; | 3159 | return ret; |
3154 | 3160 | ||
3155 | ret = verify_parent_transid(&BTRFS_I(btree_inode)->io_tree, buf, | 3161 | ret = verify_parent_transid(&BTRFS_I(btree_inode)->io_tree, buf, |
3156 | parent_transid); | 3162 | parent_transid, atomic); |
3163 | if (ret == -EAGAIN) | ||
3164 | return ret; | ||
3157 | return !ret; | 3165 | return !ret; |
3158 | } | 3166 | } |
3159 | 3167 | ||
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index a7ace1a2dd12..ab1830aaf0ed 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -66,7 +66,8 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr); | |||
66 | void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr); | 66 | void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr); |
67 | void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root); | 67 | void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root); |
68 | void btrfs_mark_buffer_dirty(struct extent_buffer *buf); | 68 | void btrfs_mark_buffer_dirty(struct extent_buffer *buf); |
69 | int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid); | 69 | int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, |
70 | int atomic); | ||
70 | int btrfs_set_buffer_uptodate(struct extent_buffer *buf); | 71 | int btrfs_set_buffer_uptodate(struct extent_buffer *buf); |
71 | int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid); | 72 | int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid); |
72 | u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len); | 73 | u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 6fc2e6f5aab8..49fd7b66d57b 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -6568,7 +6568,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans, | |||
6568 | goto skip; | 6568 | goto skip; |
6569 | } | 6569 | } |
6570 | 6570 | ||
6571 | if (!btrfs_buffer_uptodate(next, generation)) { | 6571 | if (!btrfs_buffer_uptodate(next, generation, 0)) { |
6572 | btrfs_tree_unlock(next); | 6572 | btrfs_tree_unlock(next); |
6573 | free_extent_buffer(next); | 6573 | free_extent_buffer(next); |
6574 | next = NULL; | 6574 | next = NULL; |
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 198c2ba2fa40..c9018a05036e 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -4120,6 +4120,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | |||
4120 | if (atomic_inc_not_zero(&exists->refs)) { | 4120 | if (atomic_inc_not_zero(&exists->refs)) { |
4121 | spin_unlock(&mapping->private_lock); | 4121 | spin_unlock(&mapping->private_lock); |
4122 | unlock_page(p); | 4122 | unlock_page(p); |
4123 | page_cache_release(p); | ||
4123 | mark_extent_buffer_accessed(exists); | 4124 | mark_extent_buffer_accessed(exists); |
4124 | goto free_eb; | 4125 | goto free_eb; |
4125 | } | 4126 | } |
@@ -4199,8 +4200,7 @@ free_eb: | |||
4199 | unlock_page(eb->pages[i]); | 4200 | unlock_page(eb->pages[i]); |
4200 | } | 4201 | } |
4201 | 4202 | ||
4202 | if (!atomic_dec_and_test(&eb->refs)) | 4203 | WARN_ON(!atomic_dec_and_test(&eb->refs)); |
4203 | return exists; | ||
4204 | btrfs_release_extent_buffer(eb); | 4204 | btrfs_release_extent_buffer(eb); |
4205 | return exists; | 4205 | return exists; |
4206 | } | 4206 | } |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 4f69028a68c4..086e6bdae1c4 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
@@ -252,7 +252,7 @@ struct btrfs_data_container { | |||
252 | 252 | ||
253 | struct btrfs_ioctl_ino_path_args { | 253 | struct btrfs_ioctl_ino_path_args { |
254 | __u64 inum; /* in */ | 254 | __u64 inum; /* in */ |
255 | __u32 size; /* in */ | 255 | __u64 size; /* in */ |
256 | __u64 reserved[4]; | 256 | __u64 reserved[4]; |
257 | /* struct btrfs_data_container *fspath; out */ | 257 | /* struct btrfs_data_container *fspath; out */ |
258 | __u64 fspath; /* out */ | 258 | __u64 fspath; /* out */ |
@@ -260,7 +260,7 @@ struct btrfs_ioctl_ino_path_args { | |||
260 | 260 | ||
261 | struct btrfs_ioctl_logical_ino_args { | 261 | struct btrfs_ioctl_logical_ino_args { |
262 | __u64 logical; /* in */ | 262 | __u64 logical; /* in */ |
263 | __u32 size; /* in */ | 263 | __u64 size; /* in */ |
264 | __u64 reserved[4]; | 264 | __u64 reserved[4]; |
265 | /* struct btrfs_data_container *inodes; out */ | 265 | /* struct btrfs_data_container *inodes; out */ |
266 | __u64 inodes; | 266 | __u64 inodes; |
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 4f76fc3f8e89..2f3d6f917fb3 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c | |||
@@ -998,6 +998,7 @@ static int scrub_setup_recheck_block(struct scrub_dev *sdev, | |||
998 | page = sblock->pagev + page_index; | 998 | page = sblock->pagev + page_index; |
999 | page->logical = logical; | 999 | page->logical = logical; |
1000 | page->physical = bbio->stripes[mirror_index].physical; | 1000 | page->physical = bbio->stripes[mirror_index].physical; |
1001 | /* for missing devices, bdev is NULL */ | ||
1001 | page->bdev = bbio->stripes[mirror_index].dev->bdev; | 1002 | page->bdev = bbio->stripes[mirror_index].dev->bdev; |
1002 | page->mirror_num = mirror_index + 1; | 1003 | page->mirror_num = mirror_index + 1; |
1003 | page->page = alloc_page(GFP_NOFS); | 1004 | page->page = alloc_page(GFP_NOFS); |
@@ -1042,6 +1043,12 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info, | |||
1042 | struct scrub_page *page = sblock->pagev + page_num; | 1043 | struct scrub_page *page = sblock->pagev + page_num; |
1043 | DECLARE_COMPLETION_ONSTACK(complete); | 1044 | DECLARE_COMPLETION_ONSTACK(complete); |
1044 | 1045 | ||
1046 | if (page->bdev == NULL) { | ||
1047 | page->io_error = 1; | ||
1048 | sblock->no_io_error_seen = 0; | ||
1049 | continue; | ||
1050 | } | ||
1051 | |||
1045 | BUG_ON(!page->page); | 1052 | BUG_ON(!page->page); |
1046 | bio = bio_alloc(GFP_NOFS, 1); | 1053 | bio = bio_alloc(GFP_NOFS, 1); |
1047 | if (!bio) | 1054 | if (!bio) |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index d017283ae6f5..eb1ae908582c 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -279,7 +279,7 @@ static int process_one_buffer(struct btrfs_root *log, | |||
279 | log->fs_info->extent_root, | 279 | log->fs_info->extent_root, |
280 | eb->start, eb->len); | 280 | eb->start, eb->len); |
281 | 281 | ||
282 | if (btrfs_buffer_uptodate(eb, gen)) { | 282 | if (btrfs_buffer_uptodate(eb, gen, 0)) { |
283 | if (wc->write) | 283 | if (wc->write) |
284 | btrfs_write_tree_block(eb); | 284 | btrfs_write_tree_block(eb); |
285 | if (wc->wait) | 285 | if (wc->wait) |