diff options
author | Tejun Heo <tj@kernel.org> | 2019-08-26 12:06:53 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2019-08-27 11:22:38 -0400 |
commit | 34f8fe501f0624de115d087680c84000b5d9abc9 (patch) | |
tree | 7c21102bb603a5ac0519fcfded63f9df89c25736 | |
parent | 5b9cce4c7eb0696558dfd4946074ae1fb9d8f05d (diff) |
bdi: Add bdi->id
There currently is no way to universally identify and lookup a bdi
without holding a reference and pointer to it. This patch adds an
non-recycling bdi->id and implements bdi_get_by_id() which looks up
bdis by their ids. This will be used by memcg foreign inode flushing.
I left bdi_list alone for simplicity and because while rb_tree does
support rcu assignment it doesn't seem to guarantee lossless walk when
walk is racing aginst tree rebalance operations.
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | include/linux/backing-dev-defs.h | 2 | ||||
-rw-r--r-- | include/linux/backing-dev.h | 1 | ||||
-rw-r--r-- | mm/backing-dev.c | 65 |
3 files changed, 66 insertions, 2 deletions
diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h index 8fb740178d5d..1075f2552cfc 100644 --- a/include/linux/backing-dev-defs.h +++ b/include/linux/backing-dev-defs.h | |||
@@ -185,6 +185,8 @@ struct bdi_writeback { | |||
185 | }; | 185 | }; |
186 | 186 | ||
187 | struct backing_dev_info { | 187 | struct backing_dev_info { |
188 | u64 id; | ||
189 | struct rb_node rb_node; /* keyed by ->id */ | ||
188 | struct list_head bdi_list; | 190 | struct list_head bdi_list; |
189 | unsigned long ra_pages; /* max readahead in PAGE_SIZE units */ | 191 | unsigned long ra_pages; /* max readahead in PAGE_SIZE units */ |
190 | unsigned long io_pages; /* max allowed IO size */ | 192 | unsigned long io_pages; /* max allowed IO size */ |
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 02650b1253a2..84cdcfbc763f 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h | |||
@@ -24,6 +24,7 @@ static inline struct backing_dev_info *bdi_get(struct backing_dev_info *bdi) | |||
24 | return bdi; | 24 | return bdi; |
25 | } | 25 | } |
26 | 26 | ||
27 | struct backing_dev_info *bdi_get_by_id(u64 id); | ||
27 | void bdi_put(struct backing_dev_info *bdi); | 28 | void bdi_put(struct backing_dev_info *bdi); |
28 | 29 | ||
29 | __printf(2, 3) | 30 | __printf(2, 3) |
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 | ||