diff options
Diffstat (limited to 'mm/backing-dev.c')
-rw-r--r-- | mm/backing-dev.c | 65 |
1 files changed, 63 insertions, 2 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index e8e89158adec..612aa7c5ddbd 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c | |||
@@ -1,6 +1,7 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | 1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | 2 | ||
3 | #include <linux/wait.h> | 3 | #include <linux/wait.h> |
4 | #include <linux/rbtree.h> | ||
4 | #include <linux/backing-dev.h> | 5 | #include <linux/backing-dev.h> |
5 | #include <linux/kthread.h> | 6 | #include <linux/kthread.h> |
6 | #include <linux/freezer.h> | 7 | #include <linux/freezer.h> |
@@ -22,10 +23,12 @@ EXPORT_SYMBOL_GPL(noop_backing_dev_info); | |||
22 | static struct class *bdi_class; | 23 | static struct class *bdi_class; |
23 | 24 | ||
24 | /* | 25 | /* |
25 | * bdi_lock protects updates to bdi_list. bdi_list has RCU reader side | 26 | * bdi_lock protects bdi_tree and updates to bdi_list. bdi_list has RCU |
26 | * locking. | 27 | * reader side locking. |
27 | */ | 28 | */ |
28 | DEFINE_SPINLOCK(bdi_lock); | 29 | DEFINE_SPINLOCK(bdi_lock); |
30 | static u64 bdi_id_cursor; | ||
31 | static struct rb_root bdi_tree = RB_ROOT; | ||
29 | LIST_HEAD(bdi_list); | 32 | LIST_HEAD(bdi_list); |
30 | 33 | ||
31 | /* bdi_wq serves all asynchronous writeback tasks */ | 34 | /* bdi_wq serves all asynchronous writeback tasks */ |
@@ -859,9 +862,58 @@ struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id) | |||
859 | } | 862 | } |
860 | EXPORT_SYMBOL(bdi_alloc_node); | 863 | EXPORT_SYMBOL(bdi_alloc_node); |
861 | 864 | ||
865 | static struct rb_node **bdi_lookup_rb_node(u64 id, struct rb_node **parentp) | ||
866 | { | ||
867 | struct rb_node **p = &bdi_tree.rb_node; | ||
868 | struct rb_node *parent = NULL; | ||
869 | struct backing_dev_info *bdi; | ||
870 | |||
871 | lockdep_assert_held(&bdi_lock); | ||
872 | |||
873 | while (*p) { | ||
874 | parent = *p; | ||
875 | bdi = rb_entry(parent, struct backing_dev_info, rb_node); | ||
876 | |||
877 | if (bdi->id > id) | ||
878 | p = &(*p)->rb_left; | ||
879 | else if (bdi->id < id) | ||
880 | p = &(*p)->rb_right; | ||
881 | else | ||
882 | break; | ||
883 | } | ||
884 | |||
885 | if (parentp) | ||
886 | *parentp = parent; | ||
887 | return p; | ||
888 | } | ||
889 | |||
890 | /** | ||
891 | * bdi_get_by_id - lookup and get bdi from its id | ||
892 | * @id: bdi id to lookup | ||
893 | * | ||
894 | * Find bdi matching @id and get it. Returns NULL if the matching bdi | ||
895 | * doesn't exist or is already unregistered. | ||
896 | */ | ||
897 | struct backing_dev_info *bdi_get_by_id(u64 id) | ||
898 | { | ||
899 | struct backing_dev_info *bdi = NULL; | ||
900 | struct rb_node **p; | ||
901 | |||
902 | spin_lock_bh(&bdi_lock); | ||
903 | p = bdi_lookup_rb_node(id, NULL); | ||
904 | if (*p) { | ||
905 | bdi = rb_entry(*p, struct backing_dev_info, rb_node); | ||
906 | bdi_get(bdi); | ||
907 | } | ||
908 | spin_unlock_bh(&bdi_lock); | ||
909 | |||
910 | return bdi; | ||
911 | } | ||
912 | |||
862 | int bdi_register_va(struct backing_dev_info *bdi, const char *fmt, va_list args) | 913 | int bdi_register_va(struct backing_dev_info *bdi, const char *fmt, va_list args) |
863 | { | 914 | { |
864 | struct device *dev; | 915 | struct device *dev; |
916 | struct rb_node *parent, **p; | ||
865 | 917 | ||
866 | if (bdi->dev) /* The driver needs to use separate queues per device */ | 918 | if (bdi->dev) /* The driver needs to use separate queues per device */ |
867 | return 0; | 919 | return 0; |
@@ -877,7 +929,15 @@ int bdi_register_va(struct backing_dev_info *bdi, const char *fmt, va_list args) | |||
877 | set_bit(WB_registered, &bdi->wb.state); | 929 | set_bit(WB_registered, &bdi->wb.state); |
878 | 930 | ||
879 | spin_lock_bh(&bdi_lock); | 931 | spin_lock_bh(&bdi_lock); |
932 | |||
933 | bdi->id = ++bdi_id_cursor; | ||
934 | |||
935 | p = bdi_lookup_rb_node(bdi->id, &parent); | ||
936 | rb_link_node(&bdi->rb_node, parent, p); | ||
937 | rb_insert_color(&bdi->rb_node, &bdi_tree); | ||
938 | |||
880 | list_add_tail_rcu(&bdi->bdi_list, &bdi_list); | 939 | list_add_tail_rcu(&bdi->bdi_list, &bdi_list); |
940 | |||
881 | spin_unlock_bh(&bdi_lock); | 941 | spin_unlock_bh(&bdi_lock); |
882 | 942 | ||
883 | trace_writeback_bdi_register(bdi); | 943 | trace_writeback_bdi_register(bdi); |
@@ -918,6 +978,7 @@ EXPORT_SYMBOL(bdi_register_owner); | |||
918 | static void bdi_remove_from_list(struct backing_dev_info *bdi) | 978 | static void bdi_remove_from_list(struct backing_dev_info *bdi) |
919 | { | 979 | { |
920 | spin_lock_bh(&bdi_lock); | 980 | spin_lock_bh(&bdi_lock); |
981 | rb_erase(&bdi->rb_node, &bdi_tree); | ||
921 | list_del_rcu(&bdi->bdi_list); | 982 | list_del_rcu(&bdi->bdi_list); |
922 | spin_unlock_bh(&bdi_lock); | 983 | spin_unlock_bh(&bdi_lock); |
923 | 984 | ||