aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
Diffstat (limited to 'block')
-rw-r--r--block/blk-cgroup.c236
-rw-r--r--block/blk-cgroup.h10
-rw-r--r--block/cfq-iosched.c2
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};
52EXPORT_SYMBOL_GPL(blkio_subsys); 53EXPORT_SYMBOL_GPL(blkio_subsys);
53 54
55static 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 */
62static 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 */
68static struct blkio_policy_node *
69blkio_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
54struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup) 81struct 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,
611EXPORT_SYMBOL_GPL(blkiocg_update_dequeue_stats); 645EXPORT_SYMBOL_GPL(blkiocg_update_dequeue_stats);
612#endif 646#endif
613 647
648static 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
660static 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
724unsigned 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}
735EXPORT_SYMBOL_GPL(blkcg_get_weight);
736
737
738static 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
788update_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
806free_newpn:
807 if (!keep_newpn)
808 kfree(newpn);
809free_buf:
810 kfree(buf);
811 return ret;
812}
813
814static 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
833out:
834 return 0;
835}
836
614struct cftype blkio_files[] = { 837struct 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();
695remove_entry: 925remove_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
723done: 954done:
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
75struct blkio_group_stats { 76struct 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
123struct blkio_policy_node {
124 struct list_head node;
125 dev_t dev;
126 unsigned int weight;
127};
128
129extern unsigned int blkcg_get_weight(struct blkio_cgroup *blkcg,
130 dev_t dev);
131
122typedef void (blkio_unlink_group_fn) (void *key, struct blkio_group *blkg); 132typedef void (blkio_unlink_group_fn) (void *key, struct blkio_group *blkg);
123typedef void (blkio_update_group_weight_fn) (struct blkio_group *blkg, 133typedef 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);