diff options
| -rw-r--r-- | fs/fs-writeback.c | 46 |
1 files changed, 29 insertions, 17 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 225c7316344e..c6bf775e641a 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
| @@ -540,6 +540,17 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 540 | return ret; | 540 | return ret; |
| 541 | } | 541 | } |
| 542 | 542 | ||
| 543 | static void unpin_sb_for_writeback(struct super_block **psb) | ||
| 544 | { | ||
| 545 | struct super_block *sb = *psb; | ||
| 546 | |||
| 547 | if (sb) { | ||
| 548 | up_read(&sb->s_umount); | ||
| 549 | put_super(sb); | ||
| 550 | *psb = NULL; | ||
| 551 | } | ||
| 552 | } | ||
| 553 | |||
| 543 | /* | 554 | /* |
| 544 | * For WB_SYNC_NONE writeback, the caller does not have the sb pinned | 555 | * For WB_SYNC_NONE writeback, the caller does not have the sb pinned |
| 545 | * before calling writeback. So make sure that we do pin it, so it doesn't | 556 | * before calling writeback. So make sure that we do pin it, so it doesn't |
| @@ -549,11 +560,20 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 549 | * 1 if we failed. | 560 | * 1 if we failed. |
| 550 | */ | 561 | */ |
| 551 | static int pin_sb_for_writeback(struct writeback_control *wbc, | 562 | static int pin_sb_for_writeback(struct writeback_control *wbc, |
| 552 | struct inode *inode) | 563 | struct inode *inode, struct super_block **psb) |
| 553 | { | 564 | { |
| 554 | struct super_block *sb = inode->i_sb; | 565 | struct super_block *sb = inode->i_sb; |
| 555 | 566 | ||
| 556 | /* | 567 | /* |
| 568 | * If this sb is already pinned, nothing more to do. If not and | ||
| 569 | * *psb is non-NULL, unpin the old one first | ||
| 570 | */ | ||
| 571 | if (sb == *psb) | ||
| 572 | return 0; | ||
| 573 | else if (*psb) | ||
| 574 | unpin_sb_for_writeback(psb); | ||
| 575 | |||
| 576 | /* | ||
| 557 | * Caller must already hold the ref for this | 577 | * Caller must already hold the ref for this |
| 558 | */ | 578 | */ |
| 559 | if (wbc->sync_mode == WB_SYNC_ALL) { | 579 | if (wbc->sync_mode == WB_SYNC_ALL) { |
| @@ -566,7 +586,7 @@ static int pin_sb_for_writeback(struct writeback_control *wbc, | |||
| 566 | if (down_read_trylock(&sb->s_umount)) { | 586 | if (down_read_trylock(&sb->s_umount)) { |
| 567 | if (sb->s_root) { | 587 | if (sb->s_root) { |
| 568 | spin_unlock(&sb_lock); | 588 | spin_unlock(&sb_lock); |
| 569 | return 0; | 589 | goto pinned; |
| 570 | } | 590 | } |
| 571 | /* | 591 | /* |
| 572 | * umounted, drop rwsem again and fall through to failure | 592 | * umounted, drop rwsem again and fall through to failure |
| @@ -577,24 +597,15 @@ static int pin_sb_for_writeback(struct writeback_control *wbc, | |||
| 577 | sb->s_count--; | 597 | sb->s_count--; |
| 578 | spin_unlock(&sb_lock); | 598 | spin_unlock(&sb_lock); |
| 579 | return 1; | 599 | return 1; |
| 580 | } | 600 | pinned: |
| 581 | 601 | *psb = sb; | |
| 582 | static void unpin_sb_for_writeback(struct writeback_control *wbc, | 602 | return 0; |
| 583 | struct inode *inode) | ||
| 584 | { | ||
| 585 | struct super_block *sb = inode->i_sb; | ||
| 586 | |||
| 587 | if (wbc->sync_mode == WB_SYNC_ALL) | ||
| 588 | return; | ||
| 589 | |||
| 590 | up_read(&sb->s_umount); | ||
| 591 | put_super(sb); | ||
| 592 | } | 603 | } |
| 593 | 604 | ||
| 594 | static void writeback_inodes_wb(struct bdi_writeback *wb, | 605 | static void writeback_inodes_wb(struct bdi_writeback *wb, |
| 595 | struct writeback_control *wbc) | 606 | struct writeback_control *wbc) |
| 596 | { | 607 | { |
| 597 | struct super_block *sb = wbc->sb; | 608 | struct super_block *sb = wbc->sb, *pin_sb = NULL; |
| 598 | const int is_blkdev_sb = sb_is_blkdev_sb(sb); | 609 | const int is_blkdev_sb = sb_is_blkdev_sb(sb); |
| 599 | const unsigned long start = jiffies; /* livelock avoidance */ | 610 | const unsigned long start = jiffies; /* livelock avoidance */ |
| 600 | 611 | ||
| @@ -653,7 +664,7 @@ static void writeback_inodes_wb(struct bdi_writeback *wb, | |||
| 653 | if (inode_dirtied_after(inode, start)) | 664 | if (inode_dirtied_after(inode, start)) |
| 654 | break; | 665 | break; |
| 655 | 666 | ||
| 656 | if (pin_sb_for_writeback(wbc, inode)) { | 667 | if (pin_sb_for_writeback(wbc, inode, &pin_sb)) { |
| 657 | requeue_io(inode); | 668 | requeue_io(inode); |
| 658 | continue; | 669 | continue; |
| 659 | } | 670 | } |
| @@ -662,7 +673,6 @@ static void writeback_inodes_wb(struct bdi_writeback *wb, | |||
| 662 | __iget(inode); | 673 | __iget(inode); |
| 663 | pages_skipped = wbc->pages_skipped; | 674 | pages_skipped = wbc->pages_skipped; |
| 664 | writeback_single_inode(inode, wbc); | 675 | writeback_single_inode(inode, wbc); |
| 665 | unpin_sb_for_writeback(wbc, inode); | ||
| 666 | if (wbc->pages_skipped != pages_skipped) { | 676 | if (wbc->pages_skipped != pages_skipped) { |
| 667 | /* | 677 | /* |
| 668 | * writeback is not making progress due to locked | 678 | * writeback is not making progress due to locked |
| @@ -682,6 +692,8 @@ static void writeback_inodes_wb(struct bdi_writeback *wb, | |||
| 682 | wbc->more_io = 1; | 692 | wbc->more_io = 1; |
| 683 | } | 693 | } |
| 684 | 694 | ||
| 695 | unpin_sb_for_writeback(&pin_sb); | ||
| 696 | |||
| 685 | spin_unlock(&inode_lock); | 697 | spin_unlock(&inode_lock); |
| 686 | /* Leave any unwritten inodes on b_io */ | 698 | /* Leave any unwritten inodes on b_io */ |
| 687 | } | 699 | } |
