aboutsummaryrefslogtreecommitdiffstats
path: root/mm/backing-dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/backing-dev.c')
-rw-r--r--mm/backing-dev.c43
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)
683static void cgwb_bdi_destroy(struct backing_dev_info *bdi) 683static 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
745static 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
754static int cgwb_bdi_init(struct backing_dev_info *bdi) 762static 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
772static void cgwb_bdi_destroy(struct backing_dev_info *bdi) 780static void cgwb_bdi_destroy(struct backing_dev_info *bdi) { }
781
782static 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
903static void release_bdi(struct kref *ref) 916static void release_bdi(struct kref *ref)