aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@redhat.com>2010-09-15 17:06:33 -0400
committerJens Axboe <jaxboe@fusionio.com>2010-09-16 02:42:04 -0400
commit062a644d6121d5e2f51c0b2ca0cbc5155ebf845b (patch)
tree250626a8ee11efa8e598692904e12ac26c29cab5 /block
parentaf41d7bd9b685ab4e8f930627874ba4f4728e128 (diff)
blk-cgroup: Prepare the base for supporting more than one IO control policies
o This patch prepares the base for introducing new IO control policies. Currently all the code is written knowing there is only one policy and that is proportional bandwidth. Creating infrastructure for newer policies to come in. o Also there were many functions which were generated using macro. It was very confusing. Got rid of those. Signed-off-by: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'block')
-rw-r--r--block/blk-cgroup.c544
-rw-r--r--block/blk-cgroup.h36
-rw-r--r--block/cfq-iosched.c1
-rw-r--r--block/cfq.h2
4 files changed, 429 insertions, 154 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index c1a39d90d14a..7762987fdf9e 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -37,6 +37,12 @@ static void blkiocg_attach(struct cgroup_subsys *, struct cgroup *,
37static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *); 37static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *);
38static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *); 38static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
39 39
40/* for encoding cft->private value on file */
41#define BLKIOFILE_PRIVATE(x, val) (((x) << 16) | (val))
42/* What policy owns the file, proportional or throttle */
43#define BLKIOFILE_POLICY(val) (((val) >> 16) & 0xffff)
44#define BLKIOFILE_ATTR(val) ((val) & 0xffff)
45
40struct cgroup_subsys blkio_subsys = { 46struct cgroup_subsys blkio_subsys = {
41 .name = "blkio", 47 .name = "blkio",
42 .create = blkiocg_create, 48 .create = blkiocg_create,
@@ -59,6 +65,27 @@ static inline void blkio_policy_insert_node(struct blkio_cgroup *blkcg,
59 list_add(&pn->node, &blkcg->policy_list); 65 list_add(&pn->node, &blkcg->policy_list);
60} 66}
61 67
68static inline bool cftype_blkg_same_policy(struct cftype *cft,
69 struct blkio_group *blkg)
70{
71 enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
72
73 if (blkg->plid == plid)
74 return 1;
75
76 return 0;
77}
78
79/* Determines if policy node matches cgroup file being accessed */
80static inline bool pn_matches_cftype(struct cftype *cft,
81 struct blkio_policy_node *pn)
82{
83 enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
84 int fileid = BLKIOFILE_ATTR(cft->private);
85
86 return (plid == pn->plid && fileid == pn->fileid);
87}
88
62/* Must be called with blkcg->lock held */ 89/* Must be called with blkcg->lock held */
63static inline void blkio_policy_delete_node(struct blkio_policy_node *pn) 90static inline void blkio_policy_delete_node(struct blkio_policy_node *pn)
64{ 91{
@@ -67,12 +94,13 @@ static inline void blkio_policy_delete_node(struct blkio_policy_node *pn)
67 94
68/* Must be called with blkcg->lock held */ 95/* Must be called with blkcg->lock held */
69static struct blkio_policy_node * 96static struct blkio_policy_node *
70blkio_policy_search_node(const struct blkio_cgroup *blkcg, dev_t dev) 97blkio_policy_search_node(const struct blkio_cgroup *blkcg, dev_t dev,
98 enum blkio_policy_id plid, int fileid)
71{ 99{
72 struct blkio_policy_node *pn; 100 struct blkio_policy_node *pn;
73 101
74 list_for_each_entry(pn, &blkcg->policy_list, node) { 102 list_for_each_entry(pn, &blkcg->policy_list, node) {
75 if (pn->dev == dev) 103 if (pn->dev == dev && pn->plid == plid && pn->fileid == fileid)
76 return pn; 104 return pn;
77 } 105 }
78 106
@@ -86,6 +114,20 @@ struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup)
86} 114}
87EXPORT_SYMBOL_GPL(cgroup_to_blkio_cgroup); 115EXPORT_SYMBOL_GPL(cgroup_to_blkio_cgroup);
88 116
117static inline void
118blkio_update_group_weight(struct blkio_group *blkg, unsigned int weight)
119{
120 struct blkio_policy_type *blkiop;
121
122 list_for_each_entry(blkiop, &blkio_list, list) {
123 /* If this policy does not own the blkg, do not send updates */
124 if (blkiop->plid != blkg->plid)
125 continue;
126 if (blkiop->ops.blkio_update_group_weight_fn)
127 blkiop->ops.blkio_update_group_weight_fn(blkg, weight);
128 }
129}
130
89/* 131/*
90 * Add to the appropriate stat variable depending on the request type. 132 * Add to the appropriate stat variable depending on the request type.
91 * This should be called with the blkg->stats_lock held. 133 * This should be called with the blkg->stats_lock held.
@@ -341,7 +383,8 @@ void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction,
341EXPORT_SYMBOL_GPL(blkiocg_update_io_merged_stats); 383EXPORT_SYMBOL_GPL(blkiocg_update_io_merged_stats);
342 384
343void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, 385void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
344 struct blkio_group *blkg, void *key, dev_t dev) 386 struct blkio_group *blkg, void *key, dev_t dev,
387 enum blkio_policy_id plid)
345{ 388{
346 unsigned long flags; 389 unsigned long flags;
347 390
@@ -350,6 +393,7 @@ void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
350 rcu_assign_pointer(blkg->key, key); 393 rcu_assign_pointer(blkg->key, key);
351 blkg->blkcg_id = css_id(&blkcg->css); 394 blkg->blkcg_id = css_id(&blkcg->css);
352 hlist_add_head_rcu(&blkg->blkcg_node, &blkcg->blkg_list); 395 hlist_add_head_rcu(&blkg->blkcg_node, &blkcg->blkg_list);
396 blkg->plid = plid;
353 spin_unlock_irqrestore(&blkcg->lock, flags); 397 spin_unlock_irqrestore(&blkcg->lock, flags);
354 /* Need to take css reference ? */ 398 /* Need to take css reference ? */
355 cgroup_path(blkcg->css.cgroup, blkg->path, sizeof(blkg->path)); 399 cgroup_path(blkcg->css.cgroup, blkg->path, sizeof(blkg->path));
@@ -408,51 +452,6 @@ struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key)
408} 452}
409EXPORT_SYMBOL_GPL(blkiocg_lookup_group); 453EXPORT_SYMBOL_GPL(blkiocg_lookup_group);
410 454
411#define SHOW_FUNCTION(__VAR) \
412static u64 blkiocg_##__VAR##_read(struct cgroup *cgroup, \
413 struct cftype *cftype) \
414{ \
415 struct blkio_cgroup *blkcg; \
416 \
417 blkcg = cgroup_to_blkio_cgroup(cgroup); \
418 return (u64)blkcg->__VAR; \
419}
420
421SHOW_FUNCTION(weight);
422#undef SHOW_FUNCTION
423
424static int
425blkiocg_weight_write(struct cgroup *cgroup, struct cftype *cftype, u64 val)
426{
427 struct blkio_cgroup *blkcg;
428 struct blkio_group *blkg;
429 struct hlist_node *n;
430 struct blkio_policy_type *blkiop;
431 struct blkio_policy_node *pn;
432
433 if (val < BLKIO_WEIGHT_MIN || val > BLKIO_WEIGHT_MAX)
434 return -EINVAL;
435
436 blkcg = cgroup_to_blkio_cgroup(cgroup);
437 spin_lock(&blkio_list_lock);
438 spin_lock_irq(&blkcg->lock);
439 blkcg->weight = (unsigned int)val;
440
441 hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
442 pn = blkio_policy_search_node(blkcg, blkg->dev);
443
444 if (pn)
445 continue;
446
447 list_for_each_entry(blkiop, &blkio_list, list)
448 blkiop->ops.blkio_update_group_weight_fn(blkg,
449 blkcg->weight);
450 }
451 spin_unlock_irq(&blkcg->lock);
452 spin_unlock(&blkio_list_lock);
453 return 0;
454}
455
456static int 455static int
457blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val) 456blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val)
458{ 457{
@@ -593,52 +592,6 @@ static uint64_t blkio_get_stat(struct blkio_group *blkg,
593 return disk_total; 592 return disk_total;
594} 593}
595 594
596#define SHOW_FUNCTION_PER_GROUP(__VAR, type, show_total) \
597static int blkiocg_##__VAR##_read(struct cgroup *cgroup, \
598 struct cftype *cftype, struct cgroup_map_cb *cb) \
599{ \
600 struct blkio_cgroup *blkcg; \
601 struct blkio_group *blkg; \
602 struct hlist_node *n; \
603 uint64_t cgroup_total = 0; \
604 \
605 if (!cgroup_lock_live_group(cgroup)) \
606 return -ENODEV; \
607 \
608 blkcg = cgroup_to_blkio_cgroup(cgroup); \
609 rcu_read_lock(); \
610 hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {\
611 if (blkg->dev) { \
612 spin_lock_irq(&blkg->stats_lock); \
613 cgroup_total += blkio_get_stat(blkg, cb, \
614 blkg->dev, type); \
615 spin_unlock_irq(&blkg->stats_lock); \
616 } \
617 } \
618 if (show_total) \
619 cb->fill(cb, "Total", cgroup_total); \
620 rcu_read_unlock(); \
621 cgroup_unlock(); \
622 return 0; \
623}
624
625SHOW_FUNCTION_PER_GROUP(time, BLKIO_STAT_TIME, 0);
626SHOW_FUNCTION_PER_GROUP(sectors, BLKIO_STAT_SECTORS, 0);
627SHOW_FUNCTION_PER_GROUP(io_service_bytes, BLKIO_STAT_SERVICE_BYTES, 1);
628SHOW_FUNCTION_PER_GROUP(io_serviced, BLKIO_STAT_SERVICED, 1);
629SHOW_FUNCTION_PER_GROUP(io_service_time, BLKIO_STAT_SERVICE_TIME, 1);
630SHOW_FUNCTION_PER_GROUP(io_wait_time, BLKIO_STAT_WAIT_TIME, 1);
631SHOW_FUNCTION_PER_GROUP(io_merged, BLKIO_STAT_MERGED, 1);
632SHOW_FUNCTION_PER_GROUP(io_queued, BLKIO_STAT_QUEUED, 1);
633#ifdef CONFIG_DEBUG_BLK_CGROUP
634SHOW_FUNCTION_PER_GROUP(dequeue, BLKIO_STAT_DEQUEUE, 0);
635SHOW_FUNCTION_PER_GROUP(avg_queue_size, BLKIO_STAT_AVG_QUEUE_SIZE, 0);
636SHOW_FUNCTION_PER_GROUP(group_wait_time, BLKIO_STAT_GROUP_WAIT_TIME, 0);
637SHOW_FUNCTION_PER_GROUP(idle_time, BLKIO_STAT_IDLE_TIME, 0);
638SHOW_FUNCTION_PER_GROUP(empty_time, BLKIO_STAT_EMPTY_TIME, 0);
639#endif
640#undef SHOW_FUNCTION_PER_GROUP
641
642static int blkio_check_dev_num(dev_t dev) 595static int blkio_check_dev_num(dev_t dev)
643{ 596{
644 int part = 0; 597 int part = 0;
@@ -652,7 +605,7 @@ static int blkio_check_dev_num(dev_t dev)
652} 605}
653 606
654static int blkio_policy_parse_and_set(char *buf, 607static int blkio_policy_parse_and_set(char *buf,
655 struct blkio_policy_node *newpn) 608 struct blkio_policy_node *newpn, enum blkio_policy_id plid, int fileid)
656{ 609{
657 char *s[4], *p, *major_s = NULL, *minor_s = NULL; 610 char *s[4], *p, *major_s = NULL, *minor_s = NULL;
658 int ret; 611 int ret;
@@ -705,12 +658,20 @@ static int blkio_policy_parse_and_set(char *buf,
705 if (s[1] == NULL) 658 if (s[1] == NULL)
706 return -EINVAL; 659 return -EINVAL;
707 660
708 ret = strict_strtoul(s[1], 10, &temp); 661 switch (plid) {
709 if (ret || (temp < BLKIO_WEIGHT_MIN && temp > 0) || 662 case BLKIO_POLICY_PROP:
710 temp > BLKIO_WEIGHT_MAX) 663 ret = strict_strtoul(s[1], 10, &temp);
711 return -EINVAL; 664 if (ret || (temp < BLKIO_WEIGHT_MIN && temp > 0) ||
665 temp > BLKIO_WEIGHT_MAX)
666 return -EINVAL;
712 667
713 newpn->weight = temp; 668 newpn->plid = plid;
669 newpn->fileid = fileid;
670 newpn->weight = temp;
671 break;
672 default:
673 BUG();
674 }
714 675
715 return 0; 676 return 0;
716} 677}
@@ -720,7 +681,8 @@ unsigned int blkcg_get_weight(struct blkio_cgroup *blkcg,
720{ 681{
721 struct blkio_policy_node *pn; 682 struct blkio_policy_node *pn;
722 683
723 pn = blkio_policy_search_node(blkcg, dev); 684 pn = blkio_policy_search_node(blkcg, dev, BLKIO_POLICY_PROP,
685 BLKIO_PROP_weight_device);
724 if (pn) 686 if (pn)
725 return pn->weight; 687 return pn->weight;
726 else 688 else
@@ -728,18 +690,86 @@ unsigned int blkcg_get_weight(struct blkio_cgroup *blkcg,
728} 690}
729EXPORT_SYMBOL_GPL(blkcg_get_weight); 691EXPORT_SYMBOL_GPL(blkcg_get_weight);
730 692
693/* Checks whether user asked for deleting a policy rule */
694static bool blkio_delete_rule_command(struct blkio_policy_node *pn)
695{
696 switch(pn->plid) {
697 case BLKIO_POLICY_PROP:
698 if (pn->weight == 0)
699 return 1;
700 break;
701 default:
702 BUG();
703 }
704
705 return 0;
706}
707
708static void blkio_update_policy_rule(struct blkio_policy_node *oldpn,
709 struct blkio_policy_node *newpn)
710{
711 switch(oldpn->plid) {
712 case BLKIO_POLICY_PROP:
713 oldpn->weight = newpn->weight;
714 break;
715 default:
716 BUG();
717 }
718}
719
720/*
721 * Some rules/values in blkg have changed. Propogate those to respective
722 * policies.
723 */
724static void blkio_update_blkg_policy(struct blkio_cgroup *blkcg,
725 struct blkio_group *blkg, struct blkio_policy_node *pn)
726{
727 unsigned int weight;
728
729 switch(pn->plid) {
730 case BLKIO_POLICY_PROP:
731 weight = pn->weight ? pn->weight :
732 blkcg->weight;
733 blkio_update_group_weight(blkg, weight);
734 break;
735 default:
736 BUG();
737 }
738}
731 739
732static int blkiocg_weight_device_write(struct cgroup *cgrp, struct cftype *cft, 740/*
733 const char *buffer) 741 * A policy node rule has been updated. Propogate this update to all the
742 * block groups which might be affected by this update.
743 */
744static void blkio_update_policy_node_blkg(struct blkio_cgroup *blkcg,
745 struct blkio_policy_node *pn)
746{
747 struct blkio_group *blkg;
748 struct hlist_node *n;
749
750 spin_lock(&blkio_list_lock);
751 spin_lock_irq(&blkcg->lock);
752
753 hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
754 if (pn->dev != blkg->dev || pn->plid != blkg->plid)
755 continue;
756 blkio_update_blkg_policy(blkcg, blkg, pn);
757 }
758
759 spin_unlock_irq(&blkcg->lock);
760 spin_unlock(&blkio_list_lock);
761}
762
763static int blkiocg_file_write(struct cgroup *cgrp, struct cftype *cft,
764 const char *buffer)
734{ 765{
735 int ret = 0; 766 int ret = 0;
736 char *buf; 767 char *buf;
737 struct blkio_policy_node *newpn, *pn; 768 struct blkio_policy_node *newpn, *pn;
738 struct blkio_cgroup *blkcg; 769 struct blkio_cgroup *blkcg;
739 struct blkio_group *blkg;
740 int keep_newpn = 0; 770 int keep_newpn = 0;
741 struct hlist_node *n; 771 enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
742 struct blkio_policy_type *blkiop; 772 int fileid = BLKIOFILE_ATTR(cft->private);
743 773
744 buf = kstrdup(buffer, GFP_KERNEL); 774 buf = kstrdup(buffer, GFP_KERNEL);
745 if (!buf) 775 if (!buf)
@@ -751,7 +781,7 @@ static int blkiocg_weight_device_write(struct cgroup *cgrp, struct cftype *cft,
751 goto free_buf; 781 goto free_buf;
752 } 782 }
753 783
754 ret = blkio_policy_parse_and_set(buf, newpn); 784 ret = blkio_policy_parse_and_set(buf, newpn, plid, fileid);
755 if (ret) 785 if (ret)
756 goto free_newpn; 786 goto free_newpn;
757 787
@@ -759,9 +789,9 @@ static int blkiocg_weight_device_write(struct cgroup *cgrp, struct cftype *cft,
759 789
760 spin_lock_irq(&blkcg->lock); 790 spin_lock_irq(&blkcg->lock);
761 791
762 pn = blkio_policy_search_node(blkcg, newpn->dev); 792 pn = blkio_policy_search_node(blkcg, newpn->dev, plid, fileid);
763 if (!pn) { 793 if (!pn) {
764 if (newpn->weight != 0) { 794 if (!blkio_delete_rule_command(newpn)) {
765 blkio_policy_insert_node(blkcg, newpn); 795 blkio_policy_insert_node(blkcg, newpn);
766 keep_newpn = 1; 796 keep_newpn = 1;
767 } 797 }
@@ -769,33 +799,17 @@ static int blkiocg_weight_device_write(struct cgroup *cgrp, struct cftype *cft,
769 goto update_io_group; 799 goto update_io_group;
770 } 800 }
771 801
772 if (newpn->weight == 0) { 802 if (blkio_delete_rule_command(newpn)) {
773 /* weight == 0 means deleteing a specific weight */
774 blkio_policy_delete_node(pn); 803 blkio_policy_delete_node(pn);
775 spin_unlock_irq(&blkcg->lock); 804 spin_unlock_irq(&blkcg->lock);
776 goto update_io_group; 805 goto update_io_group;
777 } 806 }
778 spin_unlock_irq(&blkcg->lock); 807 spin_unlock_irq(&blkcg->lock);
779 808
780 pn->weight = newpn->weight; 809 blkio_update_policy_rule(pn, newpn);
781 810
782update_io_group: 811update_io_group:
783 /* update weight for each cfqg */ 812 blkio_update_policy_node_blkg(blkcg, newpn);
784 spin_lock(&blkio_list_lock);
785 spin_lock_irq(&blkcg->lock);
786
787 hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
788 if (newpn->dev == blkg->dev) {
789 list_for_each_entry(blkiop, &blkio_list, list)
790 blkiop->ops.blkio_update_group_weight_fn(blkg,
791 newpn->weight ?
792 newpn->weight :
793 blkcg->weight);
794 }
795 }
796
797 spin_unlock_irq(&blkcg->lock);
798 spin_unlock(&blkio_list_lock);
799 813
800free_newpn: 814free_newpn:
801 if (!keep_newpn) 815 if (!keep_newpn)
@@ -805,21 +819,219 @@ free_buf:
805 return ret; 819 return ret;
806} 820}
807 821
808static int blkiocg_weight_device_read(struct cgroup *cgrp, struct cftype *cft, 822static void
809 struct seq_file *m) 823blkio_print_policy_node(struct seq_file *m, struct blkio_policy_node *pn)
824{
825 switch(pn->plid) {
826 case BLKIO_POLICY_PROP:
827 if (pn->fileid == BLKIO_PROP_weight_device)
828 seq_printf(m, "%u:%u\t%u\n", MAJOR(pn->dev),
829 MINOR(pn->dev), pn->weight);
830 break;
831 default:
832 BUG();
833 }
834}
835
836/* cgroup files which read their data from policy nodes end up here */
837static void blkio_read_policy_node_files(struct cftype *cft,
838 struct blkio_cgroup *blkcg, struct seq_file *m)
810{ 839{
811 struct blkio_cgroup *blkcg;
812 struct blkio_policy_node *pn; 840 struct blkio_policy_node *pn;
813 841
814 blkcg = cgroup_to_blkio_cgroup(cgrp);
815 if (!list_empty(&blkcg->policy_list)) { 842 if (!list_empty(&blkcg->policy_list)) {
816 spin_lock_irq(&blkcg->lock); 843 spin_lock_irq(&blkcg->lock);
817 list_for_each_entry(pn, &blkcg->policy_list, node) { 844 list_for_each_entry(pn, &blkcg->policy_list, node) {
818 seq_printf(m, "%u:%u\t%u\n", MAJOR(pn->dev), 845 if (!pn_matches_cftype(cft, pn))
819 MINOR(pn->dev), pn->weight); 846 continue;
847 blkio_print_policy_node(m, pn);
820 } 848 }
821 spin_unlock_irq(&blkcg->lock); 849 spin_unlock_irq(&blkcg->lock);
822 } 850 }
851}
852
853static int blkiocg_file_read(struct cgroup *cgrp, struct cftype *cft,
854 struct seq_file *m)
855{
856 struct blkio_cgroup *blkcg;
857 enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
858 int name = BLKIOFILE_ATTR(cft->private);
859
860 blkcg = cgroup_to_blkio_cgroup(cgrp);
861
862 switch(plid) {
863 case BLKIO_POLICY_PROP:
864 switch(name) {
865 case BLKIO_PROP_weight_device:
866 blkio_read_policy_node_files(cft, blkcg, m);
867 return 0;
868 default:
869 BUG();
870 }
871 break;
872 default:
873 BUG();
874 }
875
876 return 0;
877}
878
879static int blkio_read_blkg_stats(struct blkio_cgroup *blkcg,
880 struct cftype *cft, struct cgroup_map_cb *cb, enum stat_type type,
881 bool show_total)
882{
883 struct blkio_group *blkg;
884 struct hlist_node *n;
885 uint64_t cgroup_total = 0;
886
887 rcu_read_lock();
888 hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {
889 if (blkg->dev) {
890 if (!cftype_blkg_same_policy(cft, blkg))
891 continue;
892 spin_lock_irq(&blkg->stats_lock);
893 cgroup_total += blkio_get_stat(blkg, cb, blkg->dev,
894 type);
895 spin_unlock_irq(&blkg->stats_lock);
896 }
897 }
898 if (show_total)
899 cb->fill(cb, "Total", cgroup_total);
900 rcu_read_unlock();
901 return 0;
902}
903
904/* All map kind of cgroup file get serviced by this function */
905static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
906 struct cgroup_map_cb *cb)
907{
908 struct blkio_cgroup *blkcg;
909 enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
910 int name = BLKIOFILE_ATTR(cft->private);
911
912 blkcg = cgroup_to_blkio_cgroup(cgrp);
913
914 switch(plid) {
915 case BLKIO_POLICY_PROP:
916 switch(name) {
917 case BLKIO_PROP_time:
918 return blkio_read_blkg_stats(blkcg, cft, cb,
919 BLKIO_STAT_TIME, 0);
920 case BLKIO_PROP_sectors:
921 return blkio_read_blkg_stats(blkcg, cft, cb,
922 BLKIO_STAT_SECTORS, 0);
923 case BLKIO_PROP_io_service_bytes:
924 return blkio_read_blkg_stats(blkcg, cft, cb,
925 BLKIO_STAT_SERVICE_BYTES, 1);
926 case BLKIO_PROP_io_serviced:
927 return blkio_read_blkg_stats(blkcg, cft, cb,
928 BLKIO_STAT_SERVICED, 1);
929 case BLKIO_PROP_io_service_time:
930 return blkio_read_blkg_stats(blkcg, cft, cb,
931 BLKIO_STAT_SERVICE_TIME, 1);
932 case BLKIO_PROP_io_wait_time:
933 return blkio_read_blkg_stats(blkcg, cft, cb,
934 BLKIO_STAT_WAIT_TIME, 1);
935 case BLKIO_PROP_io_merged:
936 return blkio_read_blkg_stats(blkcg, cft, cb,
937 BLKIO_STAT_MERGED, 1);
938 case BLKIO_PROP_io_queued:
939 return blkio_read_blkg_stats(blkcg, cft, cb,
940 BLKIO_STAT_QUEUED, 1);
941#ifdef CONFIG_DEBUG_BLK_CGROUP
942 case BLKIO_PROP_dequeue:
943 return blkio_read_blkg_stats(blkcg, cft, cb,
944 BLKIO_STAT_DEQUEUE, 0);
945 case BLKIO_PROP_avg_queue_size:
946 return blkio_read_blkg_stats(blkcg, cft, cb,
947 BLKIO_STAT_AVG_QUEUE_SIZE, 0);
948 case BLKIO_PROP_group_wait_time:
949 return blkio_read_blkg_stats(blkcg, cft, cb,
950 BLKIO_STAT_GROUP_WAIT_TIME, 0);
951 case BLKIO_PROP_idle_time:
952 return blkio_read_blkg_stats(blkcg, cft, cb,
953 BLKIO_STAT_IDLE_TIME, 0);
954 case BLKIO_PROP_empty_time:
955 return blkio_read_blkg_stats(blkcg, cft, cb,
956 BLKIO_STAT_EMPTY_TIME, 0);
957#endif
958 default:
959 BUG();
960 }
961 break;
962
963 default:
964 BUG();
965 }
966
967 return 0;
968}
969
970static int blkio_weight_write(struct blkio_cgroup *blkcg, u64 val)
971{
972 struct blkio_group *blkg;
973 struct hlist_node *n;
974 struct blkio_policy_node *pn;
975
976 if (val < BLKIO_WEIGHT_MIN || val > BLKIO_WEIGHT_MAX)
977 return -EINVAL;
978
979 spin_lock(&blkio_list_lock);
980 spin_lock_irq(&blkcg->lock);
981 blkcg->weight = (unsigned int)val;
982
983 hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
984 pn = blkio_policy_search_node(blkcg, blkg->dev,
985 BLKIO_POLICY_PROP, BLKIO_PROP_weight_device);
986 if (pn)
987 continue;
988
989 blkio_update_group_weight(blkg, blkcg->weight);
990 }
991 spin_unlock_irq(&blkcg->lock);
992 spin_unlock(&blkio_list_lock);
993 return 0;
994}
995
996static u64 blkiocg_file_read_u64 (struct cgroup *cgrp, struct cftype *cft) {
997 struct blkio_cgroup *blkcg;
998 enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
999 int name = BLKIOFILE_ATTR(cft->private);
1000
1001 blkcg = cgroup_to_blkio_cgroup(cgrp);
1002
1003 switch(plid) {
1004 case BLKIO_POLICY_PROP:
1005 switch(name) {
1006 case BLKIO_PROP_weight:
1007 return (u64)blkcg->weight;
1008 }
1009 break;
1010 default:
1011 BUG();
1012 }
1013 return 0;
1014}
1015
1016static int
1017blkiocg_file_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val)
1018{
1019 struct blkio_cgroup *blkcg;
1020 enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
1021 int name = BLKIOFILE_ATTR(cft->private);
1022
1023 blkcg = cgroup_to_blkio_cgroup(cgrp);
1024
1025 switch(plid) {
1026 case BLKIO_POLICY_PROP:
1027 switch(name) {
1028 case BLKIO_PROP_weight:
1029 return blkio_weight_write(blkcg, val);
1030 }
1031 break;
1032 default:
1033 BUG();
1034 }
823 1035
824 return 0; 1036 return 0;
825} 1037}
@@ -827,46 +1039,66 @@ static int blkiocg_weight_device_read(struct cgroup *cgrp, struct cftype *cft,
827struct cftype blkio_files[] = { 1039struct cftype blkio_files[] = {
828 { 1040 {
829 .name = "weight_device", 1041 .name = "weight_device",
830 .read_seq_string = blkiocg_weight_device_read, 1042 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
831 .write_string = blkiocg_weight_device_write, 1043 BLKIO_PROP_weight_device),
1044 .read_seq_string = blkiocg_file_read,
1045 .write_string = blkiocg_file_write,
832 .max_write_len = 256, 1046 .max_write_len = 256,
833 }, 1047 },
834 { 1048 {
835 .name = "weight", 1049 .name = "weight",
836 .read_u64 = blkiocg_weight_read, 1050 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
837 .write_u64 = blkiocg_weight_write, 1051 BLKIO_PROP_weight),
1052 .read_u64 = blkiocg_file_read_u64,
1053 .write_u64 = blkiocg_file_write_u64,
838 }, 1054 },
839 { 1055 {
840 .name = "time", 1056 .name = "time",
841 .read_map = blkiocg_time_read, 1057 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1058 BLKIO_PROP_time),
1059 .read_map = blkiocg_file_read_map,
842 }, 1060 },
843 { 1061 {
844 .name = "sectors", 1062 .name = "sectors",
845 .read_map = blkiocg_sectors_read, 1063 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1064 BLKIO_PROP_sectors),
1065 .read_map = blkiocg_file_read_map,
846 }, 1066 },
847 { 1067 {
848 .name = "io_service_bytes", 1068 .name = "io_service_bytes",
849 .read_map = blkiocg_io_service_bytes_read, 1069 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1070 BLKIO_PROP_io_service_bytes),
1071 .read_map = blkiocg_file_read_map,
850 }, 1072 },
851 { 1073 {
852 .name = "io_serviced", 1074 .name = "io_serviced",
853 .read_map = blkiocg_io_serviced_read, 1075 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1076 BLKIO_PROP_io_serviced),
1077 .read_map = blkiocg_file_read_map,
854 }, 1078 },
855 { 1079 {
856 .name = "io_service_time", 1080 .name = "io_service_time",
857 .read_map = blkiocg_io_service_time_read, 1081 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1082 BLKIO_PROP_io_service_time),
1083 .read_map = blkiocg_file_read_map,
858 }, 1084 },
859 { 1085 {
860 .name = "io_wait_time", 1086 .name = "io_wait_time",
861 .read_map = blkiocg_io_wait_time_read, 1087 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1088 BLKIO_PROP_io_wait_time),
1089 .read_map = blkiocg_file_read_map,
862 }, 1090 },
863 { 1091 {
864 .name = "io_merged", 1092 .name = "io_merged",
865 .read_map = blkiocg_io_merged_read, 1093 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1094 BLKIO_PROP_io_merged),
1095 .read_map = blkiocg_file_read_map,
866 }, 1096 },
867 { 1097 {
868 .name = "io_queued", 1098 .name = "io_queued",
869 .read_map = blkiocg_io_queued_read, 1099 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1100 BLKIO_PROP_io_queued),
1101 .read_map = blkiocg_file_read_map,
870 }, 1102 },
871 { 1103 {
872 .name = "reset_stats", 1104 .name = "reset_stats",
@@ -875,23 +1107,33 @@ struct cftype blkio_files[] = {
875#ifdef CONFIG_DEBUG_BLK_CGROUP 1107#ifdef CONFIG_DEBUG_BLK_CGROUP
876 { 1108 {
877 .name = "avg_queue_size", 1109 .name = "avg_queue_size",
878 .read_map = blkiocg_avg_queue_size_read, 1110 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1111 BLKIO_PROP_avg_queue_size),
1112 .read_map = blkiocg_file_read_map,
879 }, 1113 },
880 { 1114 {
881 .name = "group_wait_time", 1115 .name = "group_wait_time",
882 .read_map = blkiocg_group_wait_time_read, 1116 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1117 BLKIO_PROP_group_wait_time),
1118 .read_map = blkiocg_file_read_map,
883 }, 1119 },
884 { 1120 {
885 .name = "idle_time", 1121 .name = "idle_time",
886 .read_map = blkiocg_idle_time_read, 1122 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1123 BLKIO_PROP_idle_time),
1124 .read_map = blkiocg_file_read_map,
887 }, 1125 },
888 { 1126 {
889 .name = "empty_time", 1127 .name = "empty_time",
890 .read_map = blkiocg_empty_time_read, 1128 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1129 BLKIO_PROP_empty_time),
1130 .read_map = blkiocg_file_read_map,
891 }, 1131 },
892 { 1132 {
893 .name = "dequeue", 1133 .name = "dequeue",
894 .read_map = blkiocg_dequeue_read, 1134 .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
1135 BLKIO_PROP_dequeue),
1136 .read_map = blkiocg_file_read_map,
895 }, 1137 },
896#endif 1138#endif
897}; 1139};
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index 2b866ec1dcea..c8de2598429d 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -15,6 +15,10 @@
15 15
16#include <linux/cgroup.h> 16#include <linux/cgroup.h>
17 17
18enum blkio_policy_id {
19 BLKIO_POLICY_PROP = 0, /* Proportional Bandwidth division */
20};
21
18#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE) 22#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE)
19 23
20#ifndef CONFIG_BLK_CGROUP 24#ifndef CONFIG_BLK_CGROUP
@@ -65,6 +69,25 @@ enum blkg_state_flags {
65 BLKG_empty, 69 BLKG_empty,
66}; 70};
67 71
72/* cgroup files owned by proportional weight policy */
73enum blkcg_file_name_prop {
74 BLKIO_PROP_weight = 1,
75 BLKIO_PROP_weight_device,
76 BLKIO_PROP_io_service_bytes,
77 BLKIO_PROP_io_serviced,
78 BLKIO_PROP_time,
79 BLKIO_PROP_sectors,
80 BLKIO_PROP_io_service_time,
81 BLKIO_PROP_io_wait_time,
82 BLKIO_PROP_io_merged,
83 BLKIO_PROP_io_queued,
84 BLKIO_PROP_avg_queue_size,
85 BLKIO_PROP_group_wait_time,
86 BLKIO_PROP_idle_time,
87 BLKIO_PROP_empty_time,
88 BLKIO_PROP_dequeue,
89};
90
68struct blkio_cgroup { 91struct blkio_cgroup {
69 struct cgroup_subsys_state css; 92 struct cgroup_subsys_state css;
70 unsigned int weight; 93 unsigned int weight;
@@ -112,6 +135,8 @@ struct blkio_group {
112 char path[128]; 135 char path[128];
113 /* The device MKDEV(major, minor), this group has been created for */ 136 /* The device MKDEV(major, minor), this group has been created for */
114 dev_t dev; 137 dev_t dev;
138 /* policy which owns this blk group */
139 enum blkio_policy_id plid;
115 140
116 /* Need to serialize the stats in the case of reset/update */ 141 /* Need to serialize the stats in the case of reset/update */
117 spinlock_t stats_lock; 142 spinlock_t stats_lock;
@@ -122,6 +147,10 @@ struct blkio_policy_node {
122 struct list_head node; 147 struct list_head node;
123 dev_t dev; 148 dev_t dev;
124 unsigned int weight; 149 unsigned int weight;
150 /* This node belongs to max bw policy or porportional weight policy */
151 enum blkio_policy_id plid;
152 /* cgroup file to which this rule belongs to */
153 int fileid;
125}; 154};
126 155
127extern unsigned int blkcg_get_weight(struct blkio_cgroup *blkcg, 156extern unsigned int blkcg_get_weight(struct blkio_cgroup *blkcg,
@@ -139,6 +168,7 @@ struct blkio_policy_ops {
139struct blkio_policy_type { 168struct blkio_policy_type {
140 struct list_head list; 169 struct list_head list;
141 struct blkio_policy_ops ops; 170 struct blkio_policy_ops ops;
171 enum blkio_policy_id plid;
142}; 172};
143 173
144/* Blkio controller policy registration */ 174/* Blkio controller policy registration */
@@ -212,7 +242,8 @@ static inline void blkiocg_set_start_empty_time(struct blkio_group *blkg) {}
212extern struct blkio_cgroup blkio_root_cgroup; 242extern struct blkio_cgroup blkio_root_cgroup;
213extern struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup); 243extern struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup);
214extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, 244extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
215 struct blkio_group *blkg, void *key, dev_t dev); 245 struct blkio_group *blkg, void *key, dev_t dev,
246 enum blkio_policy_id plid);
216extern int blkiocg_del_blkio_group(struct blkio_group *blkg); 247extern int blkiocg_del_blkio_group(struct blkio_group *blkg);
217extern struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, 248extern struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg,
218 void *key); 249 void *key);
@@ -234,7 +265,8 @@ static inline struct blkio_cgroup *
234cgroup_to_blkio_cgroup(struct cgroup *cgroup) { return NULL; } 265cgroup_to_blkio_cgroup(struct cgroup *cgroup) { return NULL; }
235 266
236static inline void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, 267static inline void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
237 struct blkio_group *blkg, void *key, dev_t dev) {} 268 struct blkio_group *blkg, void *key, dev_t dev,
269 enum blkio_policy_id plid) {}
238 270
239static inline int 271static inline int
240blkiocg_del_blkio_group(struct blkio_group *blkg) { return 0; } 272blkiocg_del_blkio_group(struct blkio_group *blkg) { return 0; }
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index eb4086f7dfef..b9f86190763b 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -4013,6 +4013,7 @@ static struct blkio_policy_type blkio_policy_cfq = {
4013 .blkio_unlink_group_fn = cfq_unlink_blkio_group, 4013 .blkio_unlink_group_fn = cfq_unlink_blkio_group,
4014 .blkio_update_group_weight_fn = cfq_update_blkio_group_weight, 4014 .blkio_update_group_weight_fn = cfq_update_blkio_group_weight,
4015 }, 4015 },
4016 .plid = BLKIO_POLICY_PROP,
4016}; 4017};
4017#else 4018#else
4018static struct blkio_policy_type blkio_policy_cfq; 4019static struct blkio_policy_type blkio_policy_cfq;
diff --git a/block/cfq.h b/block/cfq.h
index 93448e5a2e41..54a6d90f8e8c 100644
--- a/block/cfq.h
+++ b/block/cfq.h
@@ -69,7 +69,7 @@ static inline void cfq_blkiocg_update_completion_stats(struct blkio_group *blkg,
69 69
70static inline void cfq_blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, 70static inline void cfq_blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
71 struct blkio_group *blkg, void *key, dev_t dev) { 71 struct blkio_group *blkg, void *key, dev_t dev) {
72 blkiocg_add_blkio_group(blkcg, blkg, key, dev); 72 blkiocg_add_blkio_group(blkcg, blkg, key, dev, BLKIO_POLICY_PROP);
73} 73}
74 74
75static inline int cfq_blkiocg_del_blkio_group(struct blkio_group *blkg) 75static inline int cfq_blkiocg_del_blkio_group(struct blkio_group *blkg)