diff options
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r-- | block/cfq-iosched.c | 128 |
1 files changed, 95 insertions, 33 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index e2e6719832e1..606020fe93f3 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -1016,28 +1016,47 @@ void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg, | |||
1016 | cfqg->needs_update = true; | 1016 | cfqg->needs_update = true; |
1017 | } | 1017 | } |
1018 | 1018 | ||
1019 | static struct cfq_group * cfq_find_alloc_cfqg(struct cfq_data *cfqd, | 1019 | static void cfq_init_add_cfqg_lists(struct cfq_data *cfqd, |
1020 | struct blkio_cgroup *blkcg) | 1020 | struct cfq_group *cfqg, struct blkio_cgroup *blkcg) |
1021 | { | 1021 | { |
1022 | struct cfq_group *cfqg = NULL; | ||
1023 | void *key = cfqd; | ||
1024 | int i, j; | ||
1025 | struct cfq_rb_root *st; | ||
1026 | struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info; | 1022 | struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info; |
1027 | unsigned int major, minor; | 1023 | unsigned int major, minor; |
1028 | 1024 | ||
1029 | cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key)); | 1025 | /* |
1030 | if (cfqg && !cfqg->blkg.dev && bdi->dev && dev_name(bdi->dev)) { | 1026 | * Add group onto cgroup list. It might happen that bdi->dev is |
1027 | * not initialized yet. Initialize this new group without major | ||
1028 | * and minor info and this info will be filled in once a new thread | ||
1029 | * comes for IO. | ||
1030 | */ | ||
1031 | if (bdi->dev) { | ||
1031 | sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor); | 1032 | sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor); |
1032 | cfqg->blkg.dev = MKDEV(major, minor); | 1033 | cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, |
1033 | goto done; | 1034 | (void *)cfqd, MKDEV(major, minor)); |
1034 | } | 1035 | } else |
1035 | if (cfqg) | 1036 | cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, |
1036 | goto done; | 1037 | (void *)cfqd, 0); |
1038 | |||
1039 | cfqd->nr_blkcg_linked_grps++; | ||
1040 | cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev); | ||
1041 | |||
1042 | /* Add group on cfqd list */ | ||
1043 | hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list); | ||
1044 | } | ||
1045 | |||
1046 | /* | ||
1047 | * Should be called from sleepable context. No request queue lock as per | ||
1048 | * cpu stats are allocated dynamically and alloc_percpu needs to be called | ||
1049 | * from sleepable context. | ||
1050 | */ | ||
1051 | static struct cfq_group * cfq_alloc_cfqg(struct cfq_data *cfqd) | ||
1052 | { | ||
1053 | struct cfq_group *cfqg = NULL; | ||
1054 | int i, j; | ||
1055 | struct cfq_rb_root *st; | ||
1037 | 1056 | ||
1038 | cfqg = kzalloc_node(sizeof(*cfqg), GFP_ATOMIC, cfqd->queue->node); | 1057 | cfqg = kzalloc_node(sizeof(*cfqg), GFP_ATOMIC, cfqd->queue->node); |
1039 | if (!cfqg) | 1058 | if (!cfqg) |
1040 | goto done; | 1059 | return NULL; |
1041 | 1060 | ||
1042 | for_each_cfqg_st(cfqg, i, j, st) | 1061 | for_each_cfqg_st(cfqg, i, j, st) |
1043 | *st = CFQ_RB_ROOT; | 1062 | *st = CFQ_RB_ROOT; |
@@ -1050,28 +1069,31 @@ static struct cfq_group * cfq_find_alloc_cfqg(struct cfq_data *cfqd, | |||
1050 | * or cgroup deletion path depending on who is exiting first. | 1069 | * or cgroup deletion path depending on who is exiting first. |
1051 | */ | 1070 | */ |
1052 | cfqg->ref = 1; | 1071 | cfqg->ref = 1; |
1072 | return cfqg; | ||
1073 | } | ||
1074 | |||
1075 | static struct cfq_group * | ||
1076 | cfq_find_cfqg(struct cfq_data *cfqd, struct blkio_cgroup *blkcg) | ||
1077 | { | ||
1078 | struct cfq_group *cfqg = NULL; | ||
1079 | void *key = cfqd; | ||
1080 | struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info; | ||
1081 | unsigned int major, minor; | ||
1053 | 1082 | ||
1054 | /* | 1083 | /* |
1055 | * Add group onto cgroup list. It might happen that bdi->dev is | 1084 | * This is the common case when there are no blkio cgroups. |
1056 | * not initialized yet. Initialize this new group without major | 1085 | * Avoid lookup in this case |
1057 | * and minor info and this info will be filled in once a new thread | ||
1058 | * comes for IO. See code above. | ||
1059 | */ | 1086 | */ |
1060 | if (bdi->dev) { | 1087 | if (blkcg == &blkio_root_cgroup) |
1061 | sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor); | 1088 | cfqg = &cfqd->root_group; |
1062 | cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd, | 1089 | else |
1063 | MKDEV(major, minor)); | 1090 | cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key)); |
1064 | } else | ||
1065 | cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd, | ||
1066 | 0); | ||
1067 | |||
1068 | cfqd->nr_blkcg_linked_grps++; | ||
1069 | cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev); | ||
1070 | 1091 | ||
1071 | /* Add group on cfqd list */ | 1092 | if (cfqg && !cfqg->blkg.dev && bdi->dev && dev_name(bdi->dev)) { |
1072 | hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list); | 1093 | sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor); |
1094 | cfqg->blkg.dev = MKDEV(major, minor); | ||
1095 | } | ||
1073 | 1096 | ||
1074 | done: | ||
1075 | return cfqg; | 1097 | return cfqg; |
1076 | } | 1098 | } |
1077 | 1099 | ||
@@ -1082,13 +1104,53 @@ done: | |||
1082 | static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd) | 1104 | static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd) |
1083 | { | 1105 | { |
1084 | struct blkio_cgroup *blkcg; | 1106 | struct blkio_cgroup *blkcg; |
1085 | struct cfq_group *cfqg = NULL; | 1107 | struct cfq_group *cfqg = NULL, *__cfqg = NULL; |
1108 | struct request_queue *q = cfqd->queue; | ||
1109 | |||
1110 | rcu_read_lock(); | ||
1111 | blkcg = task_blkio_cgroup(current); | ||
1112 | cfqg = cfq_find_cfqg(cfqd, blkcg); | ||
1113 | if (cfqg) { | ||
1114 | rcu_read_unlock(); | ||
1115 | return cfqg; | ||
1116 | } | ||
1117 | |||
1118 | /* | ||
1119 | * Need to allocate a group. Allocation of group also needs allocation | ||
1120 | * of per cpu stats which in-turn takes a mutex() and can block. Hence | ||
1121 | * we need to drop rcu lock and queue_lock before we call alloc. | ||
1122 | * | ||
1123 | * Not taking any queue reference here and assuming that queue is | ||
1124 | * around by the time we return. CFQ queue allocation code does | ||
1125 | * the same. It might be racy though. | ||
1126 | */ | ||
1127 | |||
1128 | rcu_read_unlock(); | ||
1129 | spin_unlock_irq(q->queue_lock); | ||
1130 | |||
1131 | cfqg = cfq_alloc_cfqg(cfqd); | ||
1132 | |||
1133 | spin_lock_irq(q->queue_lock); | ||
1086 | 1134 | ||
1087 | rcu_read_lock(); | 1135 | rcu_read_lock(); |
1088 | blkcg = task_blkio_cgroup(current); | 1136 | blkcg = task_blkio_cgroup(current); |
1089 | cfqg = cfq_find_alloc_cfqg(cfqd, blkcg); | 1137 | |
1138 | /* | ||
1139 | * If some other thread already allocated the group while we were | ||
1140 | * not holding queue lock, free up the group | ||
1141 | */ | ||
1142 | __cfqg = cfq_find_cfqg(cfqd, blkcg); | ||
1143 | |||
1144 | if (__cfqg) { | ||
1145 | kfree(cfqg); | ||
1146 | rcu_read_unlock(); | ||
1147 | return __cfqg; | ||
1148 | } | ||
1149 | |||
1090 | if (!cfqg) | 1150 | if (!cfqg) |
1091 | cfqg = &cfqd->root_group; | 1151 | cfqg = &cfqd->root_group; |
1152 | |||
1153 | cfq_init_add_cfqg_lists(cfqd, cfqg, blkcg); | ||
1092 | rcu_read_unlock(); | 1154 | rcu_read_unlock(); |
1093 | return cfqg; | 1155 | return cfqg; |
1094 | } | 1156 | } |