diff options
Diffstat (limited to 'fs/reiserfs/stree.c')
-rw-r--r-- | fs/reiserfs/stree.c | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index d036ee5b1c81..5fa7118f04e1 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c | |||
@@ -222,9 +222,6 @@ static inline int bin_search(const void *key, /* Key to search for. */ | |||
222 | return ITEM_NOT_FOUND; | 222 | return ITEM_NOT_FOUND; |
223 | } | 223 | } |
224 | 224 | ||
225 | #ifdef CONFIG_REISERFS_CHECK | ||
226 | extern struct tree_balance *cur_tb; | ||
227 | #endif | ||
228 | 225 | ||
229 | /* Minimal possible key. It is never in the tree. */ | 226 | /* Minimal possible key. It is never in the tree. */ |
230 | const struct reiserfs_key MIN_KEY = { 0, 0, {{0, 0},} }; | 227 | const struct reiserfs_key MIN_KEY = { 0, 0, {{0, 0},} }; |
@@ -519,25 +516,48 @@ static int is_tree_node(struct buffer_head *bh, int level) | |||
519 | 516 | ||
520 | #define SEARCH_BY_KEY_READA 16 | 517 | #define SEARCH_BY_KEY_READA 16 |
521 | 518 | ||
522 | /* The function is NOT SCHEDULE-SAFE! */ | 519 | /* |
523 | static void search_by_key_reada(struct super_block *s, | 520 | * The function is NOT SCHEDULE-SAFE! |
521 | * It might unlock the write lock if we needed to wait for a block | ||
522 | * to be read. Note that in this case it won't recover the lock to avoid | ||
523 | * high contention resulting from too much lock requests, especially | ||
524 | * the caller (search_by_key) will perform other schedule-unsafe | ||
525 | * operations just after calling this function. | ||
526 | * | ||
527 | * @return true if we have unlocked | ||
528 | */ | ||
529 | static bool search_by_key_reada(struct super_block *s, | ||
524 | struct buffer_head **bh, | 530 | struct buffer_head **bh, |
525 | b_blocknr_t *b, int num) | 531 | b_blocknr_t *b, int num) |
526 | { | 532 | { |
527 | int i, j; | 533 | int i, j; |
534 | bool unlocked = false; | ||
528 | 535 | ||
529 | for (i = 0; i < num; i++) { | 536 | for (i = 0; i < num; i++) { |
530 | bh[i] = sb_getblk(s, b[i]); | 537 | bh[i] = sb_getblk(s, b[i]); |
531 | } | 538 | } |
539 | /* | ||
540 | * We are going to read some blocks on which we | ||
541 | * have a reference. It's safe, though we might be | ||
542 | * reading blocks concurrently changed if we release | ||
543 | * the lock. But it's still fine because we check later | ||
544 | * if the tree changed | ||
545 | */ | ||
532 | for (j = 0; j < i; j++) { | 546 | for (j = 0; j < i; j++) { |
533 | /* | 547 | /* |
534 | * note, this needs attention if we are getting rid of the BKL | 548 | * note, this needs attention if we are getting rid of the BKL |
535 | * you have to make sure the prepared bit isn't set on this buffer | 549 | * you have to make sure the prepared bit isn't set on this buffer |
536 | */ | 550 | */ |
537 | if (!buffer_uptodate(bh[j])) | 551 | if (!buffer_uptodate(bh[j])) { |
552 | if (!unlocked) { | ||
553 | reiserfs_write_unlock(s); | ||
554 | unlocked = true; | ||
555 | } | ||
538 | ll_rw_block(READA, 1, bh + j); | 556 | ll_rw_block(READA, 1, bh + j); |
557 | } | ||
539 | brelse(bh[j]); | 558 | brelse(bh[j]); |
540 | } | 559 | } |
560 | return unlocked; | ||
541 | } | 561 | } |
542 | 562 | ||
543 | /************************************************************************** | 563 | /************************************************************************** |
@@ -625,11 +645,26 @@ int search_by_key(struct super_block *sb, const struct cpu_key *key, /* Key to s | |||
625 | have a pointer to it. */ | 645 | have a pointer to it. */ |
626 | if ((bh = last_element->pe_buffer = | 646 | if ((bh = last_element->pe_buffer = |
627 | sb_getblk(sb, block_number))) { | 647 | sb_getblk(sb, block_number))) { |
648 | bool unlocked = false; | ||
649 | |||
628 | if (!buffer_uptodate(bh) && reada_count > 1) | 650 | if (!buffer_uptodate(bh) && reada_count > 1) |
629 | search_by_key_reada(sb, reada_bh, | 651 | /* may unlock the write lock */ |
652 | unlocked = search_by_key_reada(sb, reada_bh, | ||
630 | reada_blocks, reada_count); | 653 | reada_blocks, reada_count); |
654 | /* | ||
655 | * If we haven't already unlocked the write lock, | ||
656 | * then we need to do that here before reading | ||
657 | * the current block | ||
658 | */ | ||
659 | if (!buffer_uptodate(bh) && !unlocked) { | ||
660 | reiserfs_write_unlock(sb); | ||
661 | unlocked = true; | ||
662 | } | ||
631 | ll_rw_block(READ, 1, &bh); | 663 | ll_rw_block(READ, 1, &bh); |
632 | wait_on_buffer(bh); | 664 | wait_on_buffer(bh); |
665 | |||
666 | if (unlocked) | ||
667 | reiserfs_write_lock(sb); | ||
633 | if (!buffer_uptodate(bh)) | 668 | if (!buffer_uptodate(bh)) |
634 | goto io_error; | 669 | goto io_error; |
635 | } else { | 670 | } else { |
@@ -673,7 +708,7 @@ int search_by_key(struct super_block *sb, const struct cpu_key *key, /* Key to s | |||
673 | !key_in_buffer(search_path, key, sb), | 708 | !key_in_buffer(search_path, key, sb), |
674 | "PAP-5130: key is not in the buffer"); | 709 | "PAP-5130: key is not in the buffer"); |
675 | #ifdef CONFIG_REISERFS_CHECK | 710 | #ifdef CONFIG_REISERFS_CHECK |
676 | if (cur_tb) { | 711 | if (REISERFS_SB(sb)->cur_tb) { |
677 | print_cur_tb("5140"); | 712 | print_cur_tb("5140"); |
678 | reiserfs_panic(sb, "PAP-5140", | 713 | reiserfs_panic(sb, "PAP-5140", |
679 | "schedule occurred in do_balance!"); | 714 | "schedule occurred in do_balance!"); |
@@ -1024,7 +1059,9 @@ static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, st | |||
1024 | reiserfs_free_block(th, inode, block, 1); | 1059 | reiserfs_free_block(th, inode, block, 1); |
1025 | } | 1060 | } |
1026 | 1061 | ||
1062 | reiserfs_write_unlock(sb); | ||
1027 | cond_resched(); | 1063 | cond_resched(); |
1064 | reiserfs_write_lock(sb); | ||
1028 | 1065 | ||
1029 | if (item_moved (&s_ih, path)) { | 1066 | if (item_moved (&s_ih, path)) { |
1030 | need_re_search = 1; | 1067 | need_re_search = 1; |