diff options
Diffstat (limited to 'mm/backing-dev.c')
-rw-r--r-- | mm/backing-dev.c | 55 |
1 files changed, 37 insertions, 18 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 612aa7c5ddbd..d9daa3e422d0 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c | |||
@@ -618,13 +618,12 @@ out_put: | |||
618 | } | 618 | } |
619 | 619 | ||
620 | /** | 620 | /** |
621 | * wb_get_create - get wb for a given memcg, create if necessary | 621 | * wb_get_lookup - get wb for a given memcg |
622 | * @bdi: target bdi | 622 | * @bdi: target bdi |
623 | * @memcg_css: cgroup_subsys_state of the target memcg (must have positive ref) | 623 | * @memcg_css: cgroup_subsys_state of the target memcg (must have positive ref) |
624 | * @gfp: allocation mask to use | ||
625 | * | 624 | * |
626 | * Try to get the wb for @memcg_css on @bdi. If it doesn't exist, try to | 625 | * Try to get the wb for @memcg_css on @bdi. The returned wb has its |
627 | * create one. The returned wb has its refcount incremented. | 626 | * refcount incremented. |
628 | * | 627 | * |
629 | * This function uses css_get() on @memcg_css and thus expects its refcnt | 628 | * This function uses css_get() on @memcg_css and thus expects its refcnt |
630 | * to be positive on invocation. IOW, rcu_read_lock() protection on | 629 | * to be positive on invocation. IOW, rcu_read_lock() protection on |
@@ -641,6 +640,39 @@ out_put: | |||
641 | * each lookup. On mismatch, the existing wb is discarded and a new one is | 640 | * each lookup. On mismatch, the existing wb is discarded and a new one is |
642 | * created. | 641 | * created. |
643 | */ | 642 | */ |
643 | struct bdi_writeback *wb_get_lookup(struct backing_dev_info *bdi, | ||
644 | struct cgroup_subsys_state *memcg_css) | ||
645 | { | ||
646 | struct bdi_writeback *wb; | ||
647 | |||
648 | if (!memcg_css->parent) | ||
649 | return &bdi->wb; | ||
650 | |||
651 | rcu_read_lock(); | ||
652 | wb = radix_tree_lookup(&bdi->cgwb_tree, memcg_css->id); | ||
653 | if (wb) { | ||
654 | struct cgroup_subsys_state *blkcg_css; | ||
655 | |||
656 | /* see whether the blkcg association has changed */ | ||
657 | blkcg_css = cgroup_get_e_css(memcg_css->cgroup, &io_cgrp_subsys); | ||
658 | if (unlikely(wb->blkcg_css != blkcg_css || !wb_tryget(wb))) | ||
659 | wb = NULL; | ||
660 | css_put(blkcg_css); | ||
661 | } | ||
662 | rcu_read_unlock(); | ||
663 | |||
664 | return wb; | ||
665 | } | ||
666 | |||
667 | /** | ||
668 | * wb_get_create - get wb for a given memcg, create if necessary | ||
669 | * @bdi: target bdi | ||
670 | * @memcg_css: cgroup_subsys_state of the target memcg (must have positive ref) | ||
671 | * @gfp: allocation mask to use | ||
672 | * | ||
673 | * Try to get the wb for @memcg_css on @bdi. If it doesn't exist, try to | ||
674 | * create one. See wb_get_lookup() for more details. | ||
675 | */ | ||
644 | struct bdi_writeback *wb_get_create(struct backing_dev_info *bdi, | 676 | struct bdi_writeback *wb_get_create(struct backing_dev_info *bdi, |
645 | struct cgroup_subsys_state *memcg_css, | 677 | struct cgroup_subsys_state *memcg_css, |
646 | gfp_t gfp) | 678 | gfp_t gfp) |
@@ -653,20 +685,7 @@ struct bdi_writeback *wb_get_create(struct backing_dev_info *bdi, | |||
653 | return &bdi->wb; | 685 | return &bdi->wb; |
654 | 686 | ||
655 | do { | 687 | do { |
656 | rcu_read_lock(); | 688 | wb = wb_get_lookup(bdi, memcg_css); |
657 | wb = radix_tree_lookup(&bdi->cgwb_tree, memcg_css->id); | ||
658 | if (wb) { | ||
659 | struct cgroup_subsys_state *blkcg_css; | ||
660 | |||
661 | /* see whether the blkcg association has changed */ | ||
662 | blkcg_css = cgroup_get_e_css(memcg_css->cgroup, | ||
663 | &io_cgrp_subsys); | ||
664 | if (unlikely(wb->blkcg_css != blkcg_css || | ||
665 | !wb_tryget(wb))) | ||
666 | wb = NULL; | ||
667 | css_put(blkcg_css); | ||
668 | } | ||
669 | rcu_read_unlock(); | ||
670 | } while (!wb && !cgwb_create(bdi, memcg_css, gfp)); | 689 | } while (!wb && !cgwb_create(bdi, memcg_css, gfp)); |
671 | 690 | ||
672 | return wb; | 691 | return wb; |