diff options
author | Chris Mason <chris.mason@oracle.com> | 2012-05-06 07:23:47 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2012-05-06 07:23:47 -0400 |
commit | b9fab919b748c7b39c19ff236ed6c5682c266dde (patch) | |
tree | 49e5a6f8041a7f0a9be0c1a39cd9088e3faa1df2 /fs/btrfs/disk-io.c | |
parent | ea9947b4395fa34666086b2fa6f686e94903e047 (diff) |
Btrfs: avoid sleeping in verify_parent_transid while atomic
verify_parent_transid needs to lock the extent range to make
sure no IO is underway, and so it can safely clear the
uptodate bits if our checks fail.
But, a few callers are using it with spinlocks held. Most
of the time, the generation numbers are going to match, and
we don't want to switch to a blocking lock just for the error
case. This adds an atomic flag to verify_parent_transid,
and changes it to return EAGAIN if it needs to block to
properly verifiy things.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 18 |
1 files changed, 13 insertions, 5 deletions
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 | ||