diff options
Diffstat (limited to 'fs/reiserfs')
-rw-r--r-- | fs/reiserfs/stree.c | 42 |
1 files changed, 34 insertions, 8 deletions
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index 960c9114f6d3..6b025a42d510 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c | |||
@@ -519,12 +519,22 @@ static int is_tree_node(struct buffer_head *bh, int level) | |||
519 | 519 | ||
520 | #define SEARCH_BY_KEY_READA 16 | 520 | #define SEARCH_BY_KEY_READA 16 |
521 | 521 | ||
522 | /* The function is NOT SCHEDULE-SAFE! */ | 522 | /* |
523 | static void search_by_key_reada(struct super_block *s, | 523 | * The function is NOT SCHEDULE-SAFE! |
524 | * It might unlock the write lock if we needed to wait for a block | ||
525 | * to be read. Note that in this case it won't recover the lock to avoid | ||
526 | * high contention resulting from too much lock requests, especially | ||
527 | * the caller (search_by_key) will perform other schedule-unsafe | ||
528 | * operations just after calling this function. | ||
529 | * | ||
530 | * @return true if we have unlocked | ||
531 | */ | ||
532 | static bool search_by_key_reada(struct super_block *s, | ||
524 | struct buffer_head **bh, | 533 | struct buffer_head **bh, |
525 | b_blocknr_t *b, int num) | 534 | b_blocknr_t *b, int num) |
526 | { | 535 | { |
527 | int i, j; | 536 | int i, j; |
537 | bool unlocked = false; | ||
528 | 538 | ||
529 | for (i = 0; i < num; i++) { | 539 | for (i = 0; i < num; i++) { |
530 | bh[i] = sb_getblk(s, b[i]); | 540 | bh[i] = sb_getblk(s, b[i]); |
@@ -536,16 +546,21 @@ static void search_by_key_reada(struct super_block *s, | |||
536 | * the lock. But it's still fine because we check later | 546 | * the lock. But it's still fine because we check later |
537 | * if the tree changed | 547 | * if the tree changed |
538 | */ | 548 | */ |
539 | reiserfs_write_unlock(s); | ||
540 | for (j = 0; j < i; j++) { | 549 | for (j = 0; j < i; j++) { |
541 | /* | 550 | /* |
542 | * note, this needs attention if we are getting rid of the BKL | 551 | * note, this needs attention if we are getting rid of the BKL |
543 | * you have to make sure the prepared bit isn't set on this buffer | 552 | * you have to make sure the prepared bit isn't set on this buffer |
544 | */ | 553 | */ |
545 | if (!buffer_uptodate(bh[j])) | 554 | if (!buffer_uptodate(bh[j])) { |
555 | if (!unlocked) { | ||
556 | reiserfs_write_unlock(s); | ||
557 | unlocked = true; | ||
558 | } | ||
546 | ll_rw_block(READA, 1, bh + j); | 559 | ll_rw_block(READA, 1, bh + j); |
560 | } | ||
547 | brelse(bh[j]); | 561 | brelse(bh[j]); |
548 | } | 562 | } |
563 | return unlocked; | ||
549 | } | 564 | } |
550 | 565 | ||
551 | /************************************************************************** | 566 | /************************************************************************** |
@@ -633,15 +648,26 @@ int search_by_key(struct super_block *sb, const struct cpu_key *key, /* Key to s | |||
633 | have a pointer to it. */ | 648 | have a pointer to it. */ |
634 | if ((bh = last_element->pe_buffer = | 649 | if ((bh = last_element->pe_buffer = |
635 | sb_getblk(sb, block_number))) { | 650 | sb_getblk(sb, block_number))) { |
651 | bool unlocked = false; | ||
652 | |||
636 | if (!buffer_uptodate(bh) && reada_count > 1) | 653 | if (!buffer_uptodate(bh) && reada_count > 1) |
637 | /* will unlock the write lock */ | 654 | /* may unlock the write lock */ |
638 | search_by_key_reada(sb, reada_bh, | 655 | unlocked = search_by_key_reada(sb, reada_bh, |
639 | reada_blocks, reada_count); | 656 | reada_blocks, reada_count); |
640 | else | 657 | /* |
658 | * If we haven't already unlocked the write lock, | ||
659 | * then we need to do that here before reading | ||
660 | * the current block | ||
661 | */ | ||
662 | if (!buffer_uptodate(bh) && !unlocked) { | ||
641 | reiserfs_write_unlock(sb); | 663 | reiserfs_write_unlock(sb); |
664 | unlocked = true; | ||
665 | } | ||
642 | ll_rw_block(READ, 1, &bh); | 666 | ll_rw_block(READ, 1, &bh); |
643 | wait_on_buffer(bh); | 667 | wait_on_buffer(bh); |
644 | reiserfs_write_lock(sb); | 668 | |
669 | if (unlocked) | ||
670 | reiserfs_write_lock(sb); | ||
645 | if (!buffer_uptodate(bh)) | 671 | if (!buffer_uptodate(bh)) |
646 | goto io_error; | 672 | goto io_error; |
647 | } else { | 673 | } else { |