diff options
Diffstat (limited to 'mm/backing-dev.c')
-rw-r--r-- | mm/backing-dev.c | 43 |
1 files changed, 28 insertions, 15 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 6d861d090e9f..c6f2a37028c2 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c | |||
@@ -683,33 +683,26 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi) | |||
683 | static void cgwb_bdi_destroy(struct backing_dev_info *bdi) | 683 | static void cgwb_bdi_destroy(struct backing_dev_info *bdi) |
684 | { | 684 | { |
685 | struct radix_tree_iter iter; | 685 | struct radix_tree_iter iter; |
686 | struct rb_node *rbn; | ||
687 | void **slot; | 686 | void **slot; |
688 | 687 | ||
689 | WARN_ON(test_bit(WB_registered, &bdi->wb.state)); | 688 | WARN_ON(test_bit(WB_registered, &bdi->wb.state)); |
690 | 689 | ||
691 | spin_lock_irq(&cgwb_lock); | 690 | spin_lock_irq(&cgwb_lock); |
692 | |||
693 | radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0) | 691 | radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0) |
694 | cgwb_kill(*slot); | 692 | cgwb_kill(*slot); |
695 | |||
696 | while ((rbn = rb_first(&bdi->cgwb_congested_tree))) { | ||
697 | struct bdi_writeback_congested *congested = | ||
698 | rb_entry(rbn, struct bdi_writeback_congested, rb_node); | ||
699 | |||
700 | rb_erase(rbn, &bdi->cgwb_congested_tree); | ||
701 | congested->bdi = NULL; /* mark @congested unlinked */ | ||
702 | } | ||
703 | |||
704 | spin_unlock_irq(&cgwb_lock); | 693 | spin_unlock_irq(&cgwb_lock); |
705 | 694 | ||
706 | /* | 695 | /* |
707 | * All cgwb's and their congested states must be shutdown and | 696 | * All cgwb's must be shutdown and released before returning. Drain |
708 | * released before returning. Drain the usage counter to wait for | 697 | * the usage counter to wait for all cgwb's ever created on @bdi. |
709 | * all cgwb's and cgwb_congested's ever created on @bdi. | ||
710 | */ | 698 | */ |
711 | atomic_dec(&bdi->usage_cnt); | 699 | atomic_dec(&bdi->usage_cnt); |
712 | wait_event(cgwb_release_wait, !atomic_read(&bdi->usage_cnt)); | 700 | wait_event(cgwb_release_wait, !atomic_read(&bdi->usage_cnt)); |
701 | /* | ||
702 | * Grab back our reference so that we hold it when @bdi gets | ||
703 | * re-registered. | ||
704 | */ | ||
705 | atomic_inc(&bdi->usage_cnt); | ||
713 | } | 706 | } |
714 | 707 | ||
715 | /** | 708 | /** |
@@ -749,6 +742,21 @@ void wb_blkcg_offline(struct blkcg *blkcg) | |||
749 | spin_unlock_irq(&cgwb_lock); | 742 | spin_unlock_irq(&cgwb_lock); |
750 | } | 743 | } |
751 | 744 | ||
745 | static void cgwb_bdi_exit(struct backing_dev_info *bdi) | ||
746 | { | ||
747 | struct rb_node *rbn; | ||
748 | |||
749 | spin_lock_irq(&cgwb_lock); | ||
750 | while ((rbn = rb_first(&bdi->cgwb_congested_tree))) { | ||
751 | struct bdi_writeback_congested *congested = | ||
752 | rb_entry(rbn, struct bdi_writeback_congested, rb_node); | ||
753 | |||
754 | rb_erase(rbn, &bdi->cgwb_congested_tree); | ||
755 | congested->bdi = NULL; /* mark @congested unlinked */ | ||
756 | } | ||
757 | spin_unlock_irq(&cgwb_lock); | ||
758 | } | ||
759 | |||
752 | #else /* CONFIG_CGROUP_WRITEBACK */ | 760 | #else /* CONFIG_CGROUP_WRITEBACK */ |
753 | 761 | ||
754 | static int cgwb_bdi_init(struct backing_dev_info *bdi) | 762 | static int cgwb_bdi_init(struct backing_dev_info *bdi) |
@@ -769,7 +777,9 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi) | |||
769 | return 0; | 777 | return 0; |
770 | } | 778 | } |
771 | 779 | ||
772 | static void cgwb_bdi_destroy(struct backing_dev_info *bdi) | 780 | static void cgwb_bdi_destroy(struct backing_dev_info *bdi) { } |
781 | |||
782 | static void cgwb_bdi_exit(struct backing_dev_info *bdi) | ||
773 | { | 783 | { |
774 | wb_congested_put(bdi->wb_congested); | 784 | wb_congested_put(bdi->wb_congested); |
775 | } | 785 | } |
@@ -857,6 +867,8 @@ int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner) | |||
857 | MINOR(owner->devt)); | 867 | MINOR(owner->devt)); |
858 | if (rc) | 868 | if (rc) |
859 | return rc; | 869 | return rc; |
870 | /* Leaking owner reference... */ | ||
871 | WARN_ON(bdi->owner); | ||
860 | bdi->owner = owner; | 872 | bdi->owner = owner; |
861 | get_device(owner); | 873 | get_device(owner); |
862 | return 0; | 874 | return 0; |
@@ -898,6 +910,7 @@ static void bdi_exit(struct backing_dev_info *bdi) | |||
898 | { | 910 | { |
899 | WARN_ON_ONCE(bdi->dev); | 911 | WARN_ON_ONCE(bdi->dev); |
900 | wb_exit(&bdi->wb); | 912 | wb_exit(&bdi->wb); |
913 | cgwb_bdi_exit(bdi); | ||
901 | } | 914 | } |
902 | 915 | ||
903 | static void release_bdi(struct kref *ref) | 916 | static void release_bdi(struct kref *ref) |