diff options
-rw-r--r-- | block/blk-cgroup.c | 236 | ||||
-rw-r--r-- | block/blk-cgroup.h | 10 | ||||
-rw-r--r-- | block/cfq-iosched.c | 2 |
3 files changed, 247 insertions, 1 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 1ecff7a39f2c..649b05d7f291 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | #include <linux/blkdev.h> | 18 | #include <linux/blkdev.h> |
19 | #include "blk-cgroup.h" | 19 | #include "blk-cgroup.h" |
20 | #include <linux/genhd.h> | ||
20 | 21 | ||
21 | #define MAX_KEY_LEN 100 | 22 | #define MAX_KEY_LEN 100 |
22 | 23 | ||
@@ -51,6 +52,32 @@ struct cgroup_subsys blkio_subsys = { | |||
51 | }; | 52 | }; |
52 | EXPORT_SYMBOL_GPL(blkio_subsys); | 53 | EXPORT_SYMBOL_GPL(blkio_subsys); |
53 | 54 | ||
55 | static inline void blkio_policy_insert_node(struct blkio_cgroup *blkcg, | ||
56 | struct blkio_policy_node *pn) | ||
57 | { | ||
58 | list_add(&pn->node, &blkcg->policy_list); | ||
59 | } | ||
60 | |||
61 | /* Must be called with blkcg->lock held */ | ||
62 | static inline void blkio_policy_delete_node(struct blkio_policy_node *pn) | ||
63 | { | ||
64 | list_del(&pn->node); | ||
65 | } | ||
66 | |||
67 | /* Must be called with blkcg->lock held */ | ||
68 | static struct blkio_policy_node * | ||
69 | blkio_policy_search_node(const struct blkio_cgroup *blkcg, dev_t dev) | ||
70 | { | ||
71 | struct blkio_policy_node *pn; | ||
72 | |||
73 | list_for_each_entry(pn, &blkcg->policy_list, node) { | ||
74 | if (pn->dev == dev) | ||
75 | return pn; | ||
76 | } | ||
77 | |||
78 | return NULL; | ||
79 | } | ||
80 | |||
54 | struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup) | 81 | struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup) |
55 | { | 82 | { |
56 | return container_of(cgroup_subsys_state(cgroup, blkio_subsys_id), | 83 | return container_of(cgroup_subsys_state(cgroup, blkio_subsys_id), |
@@ -398,6 +425,7 @@ blkiocg_weight_write(struct cgroup *cgroup, struct cftype *cftype, u64 val) | |||
398 | struct blkio_group *blkg; | 425 | struct blkio_group *blkg; |
399 | struct hlist_node *n; | 426 | struct hlist_node *n; |
400 | struct blkio_policy_type *blkiop; | 427 | struct blkio_policy_type *blkiop; |
428 | struct blkio_policy_node *pn; | ||
401 | 429 | ||
402 | if (val < BLKIO_WEIGHT_MIN || val > BLKIO_WEIGHT_MAX) | 430 | if (val < BLKIO_WEIGHT_MIN || val > BLKIO_WEIGHT_MAX) |
403 | return -EINVAL; | 431 | return -EINVAL; |
@@ -406,7 +434,13 @@ blkiocg_weight_write(struct cgroup *cgroup, struct cftype *cftype, u64 val) | |||
406 | spin_lock(&blkio_list_lock); | 434 | spin_lock(&blkio_list_lock); |
407 | spin_lock_irq(&blkcg->lock); | 435 | spin_lock_irq(&blkcg->lock); |
408 | blkcg->weight = (unsigned int)val; | 436 | blkcg->weight = (unsigned int)val; |
437 | |||
409 | hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) { | 438 | hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) { |
439 | pn = blkio_policy_search_node(blkcg, blkg->dev); | ||
440 | |||
441 | if (pn) | ||
442 | continue; | ||
443 | |||
410 | list_for_each_entry(blkiop, &blkio_list, list) | 444 | list_for_each_entry(blkiop, &blkio_list, list) |
411 | blkiop->ops.blkio_update_group_weight_fn(blkg, | 445 | blkiop->ops.blkio_update_group_weight_fn(blkg, |
412 | blkcg->weight); | 446 | blkcg->weight); |
@@ -611,8 +645,203 @@ void blkiocg_update_dequeue_stats(struct blkio_group *blkg, | |||
611 | EXPORT_SYMBOL_GPL(blkiocg_update_dequeue_stats); | 645 | EXPORT_SYMBOL_GPL(blkiocg_update_dequeue_stats); |
612 | #endif | 646 | #endif |
613 | 647 | ||
648 | static int blkio_check_dev_num(dev_t dev) | ||
649 | { | ||
650 | int part = 0; | ||
651 | struct gendisk *disk; | ||
652 | |||
653 | disk = get_gendisk(dev, &part); | ||
654 | if (!disk || part) | ||
655 | return -ENODEV; | ||
656 | |||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | static int blkio_policy_parse_and_set(char *buf, | ||
661 | struct blkio_policy_node *newpn) | ||
662 | { | ||
663 | char *s[4], *p, *major_s = NULL, *minor_s = NULL; | ||
664 | int ret; | ||
665 | unsigned long major, minor, temp; | ||
666 | int i = 0; | ||
667 | dev_t dev; | ||
668 | |||
669 | memset(s, 0, sizeof(s)); | ||
670 | |||
671 | while ((p = strsep(&buf, " ")) != NULL) { | ||
672 | if (!*p) | ||
673 | continue; | ||
674 | |||
675 | s[i++] = p; | ||
676 | |||
677 | /* Prevent from inputing too many things */ | ||
678 | if (i == 3) | ||
679 | break; | ||
680 | } | ||
681 | |||
682 | if (i != 2) | ||
683 | return -EINVAL; | ||
684 | |||
685 | p = strsep(&s[0], ":"); | ||
686 | if (p != NULL) | ||
687 | major_s = p; | ||
688 | else | ||
689 | return -EINVAL; | ||
690 | |||
691 | minor_s = s[0]; | ||
692 | if (!minor_s) | ||
693 | return -EINVAL; | ||
694 | |||
695 | ret = strict_strtoul(major_s, 10, &major); | ||
696 | if (ret) | ||
697 | return -EINVAL; | ||
698 | |||
699 | ret = strict_strtoul(minor_s, 10, &minor); | ||
700 | if (ret) | ||
701 | return -EINVAL; | ||
702 | |||
703 | dev = MKDEV(major, minor); | ||
704 | |||
705 | ret = blkio_check_dev_num(dev); | ||
706 | if (ret) | ||
707 | return ret; | ||
708 | |||
709 | newpn->dev = dev; | ||
710 | |||
711 | if (s[1] == NULL) | ||
712 | return -EINVAL; | ||
713 | |||
714 | ret = strict_strtoul(s[1], 10, &temp); | ||
715 | if (ret || (temp < BLKIO_WEIGHT_MIN && temp > 0) || | ||
716 | temp > BLKIO_WEIGHT_MAX) | ||
717 | return -EINVAL; | ||
718 | |||
719 | newpn->weight = temp; | ||
720 | |||
721 | return 0; | ||
722 | } | ||
723 | |||
724 | unsigned int blkcg_get_weight(struct blkio_cgroup *blkcg, | ||
725 | dev_t dev) | ||
726 | { | ||
727 | struct blkio_policy_node *pn; | ||
728 | |||
729 | pn = blkio_policy_search_node(blkcg, dev); | ||
730 | if (pn) | ||
731 | return pn->weight; | ||
732 | else | ||
733 | return blkcg->weight; | ||
734 | } | ||
735 | EXPORT_SYMBOL_GPL(blkcg_get_weight); | ||
736 | |||
737 | |||
738 | static int blkiocg_weight_device_write(struct cgroup *cgrp, struct cftype *cft, | ||
739 | const char *buffer) | ||
740 | { | ||
741 | int ret = 0; | ||
742 | char *buf; | ||
743 | struct blkio_policy_node *newpn, *pn; | ||
744 | struct blkio_cgroup *blkcg; | ||
745 | struct blkio_group *blkg; | ||
746 | int keep_newpn = 0; | ||
747 | struct hlist_node *n; | ||
748 | struct blkio_policy_type *blkiop; | ||
749 | |||
750 | buf = kstrdup(buffer, GFP_KERNEL); | ||
751 | if (!buf) | ||
752 | return -ENOMEM; | ||
753 | |||
754 | newpn = kzalloc(sizeof(*newpn), GFP_KERNEL); | ||
755 | if (!newpn) { | ||
756 | ret = -ENOMEM; | ||
757 | goto free_buf; | ||
758 | } | ||
759 | |||
760 | ret = blkio_policy_parse_and_set(buf, newpn); | ||
761 | if (ret) | ||
762 | goto free_newpn; | ||
763 | |||
764 | blkcg = cgroup_to_blkio_cgroup(cgrp); | ||
765 | |||
766 | spin_lock_irq(&blkcg->lock); | ||
767 | |||
768 | pn = blkio_policy_search_node(blkcg, newpn->dev); | ||
769 | if (!pn) { | ||
770 | if (newpn->weight != 0) { | ||
771 | blkio_policy_insert_node(blkcg, newpn); | ||
772 | keep_newpn = 1; | ||
773 | } | ||
774 | spin_unlock_irq(&blkcg->lock); | ||
775 | goto update_io_group; | ||
776 | } | ||
777 | |||
778 | if (newpn->weight == 0) { | ||
779 | /* weight == 0 means deleteing a specific weight */ | ||
780 | blkio_policy_delete_node(pn); | ||
781 | spin_unlock_irq(&blkcg->lock); | ||
782 | goto update_io_group; | ||
783 | } | ||
784 | spin_unlock_irq(&blkcg->lock); | ||
785 | |||
786 | pn->weight = newpn->weight; | ||
787 | |||
788 | update_io_group: | ||
789 | /* update weight for each cfqg */ | ||
790 | spin_lock(&blkio_list_lock); | ||
791 | spin_lock_irq(&blkcg->lock); | ||
792 | |||
793 | hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) { | ||
794 | if (newpn->dev == blkg->dev) { | ||
795 | list_for_each_entry(blkiop, &blkio_list, list) | ||
796 | blkiop->ops.blkio_update_group_weight_fn(blkg, | ||
797 | newpn->weight ? | ||
798 | newpn->weight : | ||
799 | blkcg->weight); | ||
800 | } | ||
801 | } | ||
802 | |||
803 | spin_unlock_irq(&blkcg->lock); | ||
804 | spin_unlock(&blkio_list_lock); | ||
805 | |||
806 | free_newpn: | ||
807 | if (!keep_newpn) | ||
808 | kfree(newpn); | ||
809 | free_buf: | ||
810 | kfree(buf); | ||
811 | return ret; | ||
812 | } | ||
813 | |||
814 | static int blkiocg_weight_device_read(struct cgroup *cgrp, struct cftype *cft, | ||
815 | struct seq_file *m) | ||
816 | { | ||
817 | struct blkio_cgroup *blkcg; | ||
818 | struct blkio_policy_node *pn; | ||
819 | |||
820 | seq_printf(m, "dev\tweight\n"); | ||
821 | |||
822 | blkcg = cgroup_to_blkio_cgroup(cgrp); | ||
823 | if (list_empty(&blkcg->policy_list)) | ||
824 | goto out; | ||
825 | |||
826 | spin_lock_irq(&blkcg->lock); | ||
827 | list_for_each_entry(pn, &blkcg->policy_list, node) { | ||
828 | seq_printf(m, "%u:%u\t%u\n", MAJOR(pn->dev), | ||
829 | MINOR(pn->dev), pn->weight); | ||
830 | } | ||
831 | spin_unlock_irq(&blkcg->lock); | ||
832 | |||
833 | out: | ||
834 | return 0; | ||
835 | } | ||
836 | |||
614 | struct cftype blkio_files[] = { | 837 | struct cftype blkio_files[] = { |
615 | { | 838 | { |
839 | .name = "weight_device", | ||
840 | .read_seq_string = blkiocg_weight_device_read, | ||
841 | .write_string = blkiocg_weight_device_write, | ||
842 | .max_write_len = 256, | ||
843 | }, | ||
844 | { | ||
616 | .name = "weight", | 845 | .name = "weight", |
617 | .read_u64 = blkiocg_weight_read, | 846 | .read_u64 = blkiocg_weight_read, |
618 | .write_u64 = blkiocg_weight_write, | 847 | .write_u64 = blkiocg_weight_write, |
@@ -690,6 +919,7 @@ static void blkiocg_destroy(struct cgroup_subsys *subsys, struct cgroup *cgroup) | |||
690 | struct blkio_group *blkg; | 919 | struct blkio_group *blkg; |
691 | void *key; | 920 | void *key; |
692 | struct blkio_policy_type *blkiop; | 921 | struct blkio_policy_type *blkiop; |
922 | struct blkio_policy_node *pn, *pntmp; | ||
693 | 923 | ||
694 | rcu_read_lock(); | 924 | rcu_read_lock(); |
695 | remove_entry: | 925 | remove_entry: |
@@ -720,7 +950,12 @@ remove_entry: | |||
720 | blkiop->ops.blkio_unlink_group_fn(key, blkg); | 950 | blkiop->ops.blkio_unlink_group_fn(key, blkg); |
721 | spin_unlock(&blkio_list_lock); | 951 | spin_unlock(&blkio_list_lock); |
722 | goto remove_entry; | 952 | goto remove_entry; |
953 | |||
723 | done: | 954 | done: |
955 | list_for_each_entry_safe(pn, pntmp, &blkcg->policy_list, node) { | ||
956 | blkio_policy_delete_node(pn); | ||
957 | kfree(pn); | ||
958 | } | ||
724 | free_css_id(&blkio_subsys, &blkcg->css); | 959 | free_css_id(&blkio_subsys, &blkcg->css); |
725 | rcu_read_unlock(); | 960 | rcu_read_unlock(); |
726 | if (blkcg != &blkio_root_cgroup) | 961 | if (blkcg != &blkio_root_cgroup) |
@@ -751,6 +986,7 @@ done: | |||
751 | spin_lock_init(&blkcg->lock); | 986 | spin_lock_init(&blkcg->lock); |
752 | INIT_HLIST_HEAD(&blkcg->blkg_list); | 987 | INIT_HLIST_HEAD(&blkcg->blkg_list); |
753 | 988 | ||
989 | INIT_LIST_HEAD(&blkcg->policy_list); | ||
754 | return &blkcg->css; | 990 | return &blkcg->css; |
755 | } | 991 | } |
756 | 992 | ||
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h index bfce085b1962..3c27bdfc97b9 100644 --- a/block/blk-cgroup.h +++ b/block/blk-cgroup.h | |||
@@ -70,6 +70,7 @@ struct blkio_cgroup { | |||
70 | unsigned int weight; | 70 | unsigned int weight; |
71 | spinlock_t lock; | 71 | spinlock_t lock; |
72 | struct hlist_head blkg_list; | 72 | struct hlist_head blkg_list; |
73 | struct list_head policy_list; /* list of blkio_policy_node */ | ||
73 | }; | 74 | }; |
74 | 75 | ||
75 | struct blkio_group_stats { | 76 | struct blkio_group_stats { |
@@ -119,6 +120,15 @@ struct blkio_group { | |||
119 | struct blkio_group_stats stats; | 120 | struct blkio_group_stats stats; |
120 | }; | 121 | }; |
121 | 122 | ||
123 | struct blkio_policy_node { | ||
124 | struct list_head node; | ||
125 | dev_t dev; | ||
126 | unsigned int weight; | ||
127 | }; | ||
128 | |||
129 | extern unsigned int blkcg_get_weight(struct blkio_cgroup *blkcg, | ||
130 | dev_t dev); | ||
131 | |||
122 | typedef void (blkio_unlink_group_fn) (void *key, struct blkio_group *blkg); | 132 | typedef void (blkio_unlink_group_fn) (void *key, struct blkio_group *blkg); |
123 | typedef void (blkio_update_group_weight_fn) (struct blkio_group *blkg, | 133 | typedef void (blkio_update_group_weight_fn) (struct blkio_group *blkg, |
124 | unsigned int weight); | 134 | unsigned int weight); |
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index b6e095c7ef5e..91af2f2e59ce 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -952,7 +952,6 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create) | |||
952 | if (!cfqg) | 952 | if (!cfqg) |
953 | goto done; | 953 | goto done; |
954 | 954 | ||
955 | cfqg->weight = blkcg->weight; | ||
956 | for_each_cfqg_st(cfqg, i, j, st) | 955 | for_each_cfqg_st(cfqg, i, j, st) |
957 | *st = CFQ_RB_ROOT; | 956 | *st = CFQ_RB_ROOT; |
958 | RB_CLEAR_NODE(&cfqg->rb_node); | 957 | RB_CLEAR_NODE(&cfqg->rb_node); |
@@ -970,6 +969,7 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create) | |||
970 | sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor); | 969 | sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor); |
971 | blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd, | 970 | blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd, |
972 | MKDEV(major, minor)); | 971 | MKDEV(major, minor)); |
972 | cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev); | ||
973 | 973 | ||
974 | /* Add group on cfqd list */ | 974 | /* Add group on cfqd list */ |
975 | hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list); | 975 | hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list); |