add patches

This commit is contained in:
Ertuğrul Erata
2017-05-09 21:54:58 +03:00
parent 8d634eded9
commit 618f68d441
13 changed files with 1414 additions and 289 deletions
@@ -1,6 +1,6 @@
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86_64 4.9.21 Kernel Configuration
# Linux/x86_64 4.9.27 Kernel Configuration
#
CONFIG_64BIT=y
CONFIG_X86_64=y
Binary file not shown.
@@ -1,9 +1,13 @@
From 3e3791c0b4ef3b2067f8454e58001af8e3da3840 Mon Sep 17 00:00:00 2001
From 0432a5c7bfc4a11531c1e58f574c733a2552f149 Mon Sep 17 00:00:00 2001
From: Paolo Valente <paolo.valente@linaro.org>
Date: Tue, 17 May 2016 08:28:04 +0200
Subject: [PATCH 4/4] Turn into BFQ-v8r6 for 4.9.0
Subject: [PATCH 4/4] Turn into BFQ-v8r7 for 4.9.0
CHANGELOG from v8r4 to v8r6
CHANGELOG from v8r4 to v8r7
BFQ v8r7
BUGFIX: make BFQ compile also without hierarchical support
BFQ v8r6
@@ -125,9 +129,9 @@ Signed-off-by: Paolo Valente <paolo.valente@linaro.org>
block/Kconfig.iosched | 18 +-
block/bfq-cgroup.c | 501 +++---
block/bfq-iosched.c | 3278 ++++++++++++++++++++++-------------
block/bfq-sched.c | 1270 +++++++++++---
block/bfq-sched.c | 1288 +++++++++++---
block/bfq.h | 800 +++++----
7 files changed, 4310 insertions(+), 2089 deletions(-)
7 files changed, 4320 insertions(+), 2097 deletions(-)
create mode 100644 Documentation/block/bfq-iosched.txt
diff --git a/Documentation/block/00-INDEX b/Documentation/block/00-INDEX
@@ -1601,7 +1605,7 @@ index 0367996..bbaecd0 100644
static struct bfq_group *
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index cf3e9b1..0f9cd53 100644
index cf3e9b1..2a2c130 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -1,5 +1,5 @@
@@ -6201,7 +6205,7 @@ index cf3e9b1..0f9cd53 100644
-
- if (bfq_timeout_async == 0)
- bfq_timeout_async = 1;
+ char msg[60] = "BFQ I/O-scheduler: v8r6";
+ char msg[60] = "BFQ I/O-scheduler: v8r7";
#ifdef CONFIG_BFQ_GROUP_IOSCHED
ret = blkcg_policy_register(&blkcg_policy_bfq);
@@ -6265,10 +6269,10 @@ index cf3e9b1..0f9cd53 100644
return 0;
diff --git a/block/bfq-sched.c b/block/bfq-sched.c
index a5ed694..4af77f4 100644
index a5ed694..797bce7 100644
--- a/block/bfq-sched.c
+++ b/block/bfq-sched.c
@@ -7,28 +7,46 @@
@@ -7,28 +7,166 @@
* Copyright (C) 2008 Fabio Checconi <fabio@gandalf.sssup.it>
* Paolo Valente <paolo.valente@unimore.it>
*
@@ -6276,8 +6280,8 @@ index a5ed694..4af77f4 100644
+ * Copyright (C) 2015 Paolo Valente <paolo.valente@unimore.it>
+ *
+ * Copyright (C) 2016 Paolo Valente <paolo.valente@linaro.org>
*/
+ */
+
+static struct bfq_group *bfqq_group(struct bfq_queue *bfqq);
+
+/**
@@ -6292,63 +6296,17 @@ index a5ed694..4af77f4 100644
+ return (s64)(a - b) > 0;
+}
+
#ifdef CONFIG_BFQ_GROUP_IOSCHED
-#define for_each_entity(entity) \
+/* both next loops stop at one of the child entities of the root group */
+#define for_each_entity(entity) \
for (; entity ; entity = entity->parent)
#define for_each_entity_safe(entity, parent) \
for (; entity && ({ parent = entity->parent; 1; }); entity = parent)
-static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd,
- int extract,
- struct bfq_data *bfqd);
-
-static struct bfq_group *bfqq_group(struct bfq_queue *bfqq);
+static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd);
-static void bfq_update_budget(struct bfq_entity *next_in_service)
+/*
+ * Returns true if this budget changes may let next_in_service->parent
+ * become the next_in_service entity for its parent entity.
+ */
+static bool bfq_update_parent_budget(struct bfq_entity *next_in_service)
{
struct bfq_entity *bfqg_entity;
struct bfq_group *bfqg;
struct bfq_sched_data *group_sd;
+ bool ret = false;
BUG_ON(!next_in_service);
@@ -41,39 +59,134 @@ static void bfq_update_budget(struct bfq_entity *next_in_service)
* as it must never become an in-service entity.
*/
bfqg_entity = bfqg->my_entity;
- if (bfqg_entity)
+ if (bfqg_entity) {
+ if (bfqg_entity->budget > next_in_service->budget)
+ ret = true;
bfqg_entity->budget = next_in_service->budget;
+ }
+
+ return ret;
}
-static int bfq_update_next_in_service(struct bfq_sched_data *sd)
+static struct bfq_entity *bfq_root_active_entity(struct rb_root *tree)
{
- struct bfq_entity *next_in_service;
+{
+ struct rb_node *node = tree->rb_node;
- if (sd->in_service_entity)
- /* will update/requeue at the end of service */
- return 0;
+
+ return rb_entry(node, struct bfq_entity, rb_node);
+}
+
+static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd);
+
+static bool bfq_update_parent_budget(struct bfq_entity *next_in_service);
+
+/**
+ * bfq_update_next_in_service - update sd->next_in_service
+ * @sd: sched_data for which to perform the update.
@@ -6371,20 +6329,15 @@ index a5ed694..4af77f4 100644
+ * Returns true if sd->next_in_service changes in such a way that
+ * entity->parent may become the next_in_service for its parent
+ * entity.
+ */
*/
+static bool bfq_update_next_in_service(struct bfq_sched_data *sd,
+ struct bfq_entity *new_entity)
+{
+ struct bfq_entity *next_in_service = sd->next_in_service;
+ struct bfq_queue *bfqq;
+ bool parent_sched_may_change = false;
/*
- * NOTE: this can be improved in many ways, such as returning
- * 1 (and thus propagating upwards the update) only when the
- * budget changes, or caching the bfqq that will be scheduled
- * next from this subtree. By now we worry more about
- * correctness than about performance...
+
+ /*
+ * If this update is triggered by the activation, requeueing
+ * or repositiong of an entity that does not coincide with
+ * sd->next_in_service, then a full lookup in the active tree
@@ -6395,8 +6348,7 @@ index a5ed694..4af77f4 100644
+ * finish time than sd->next_in_service. If this compound
+ * condition holds, then the new entity becomes the new
+ * next_in_service. Otherwise no change is needed.
*/
- next_in_service = bfq_lookup_next_entity(sd, 0, NULL);
+ */
+ if (new_entity && new_entity != sd->next_in_service) {
+ /*
+ * Flag used to decide whether to replace
@@ -6445,54 +6397,160 @@ index a5ed694..4af77f4 100644
+ bfq_update_parent_budget(next_in_service);
+ }
+
sd->next_in_service = next_in_service;
- if (next_in_service)
- bfq_update_budget(next_in_service);
+ sd->next_in_service = next_in_service;
+
+ if (!next_in_service)
+ return parent_sched_may_change;
- return 1;
-}
+ bfqq = bfq_entity_to_bfqq(next_in_service);
+ if (bfqq)
+ bfq_log_bfqq(bfqq->bfqd, bfqq,
+ "update_next_in_service: chosen this queue");
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
#ifdef CONFIG_BFQ_GROUP_IOSCHED
-#define for_each_entity(entity) \
+ else {
+ struct bfq_group *bfqg =
+ container_of(next_in_service,
+ struct bfq_group, entity);
-static void bfq_check_next_in_service(struct bfq_sched_data *sd,
- struct bfq_entity *entity)
-{
- BUG_ON(sd->next_in_service != entity);
+
+ bfq_log_bfqg((struct bfq_data *)bfqg->bfqd, bfqg,
+ "update_next_in_service: chosen this entity");
+ }
+#endif
+ return parent_sched_may_change;
}
+}
+
#else
#define for_each_entity(entity) \
for (; entity ; entity = NULL)
@@ -86,12 +199,7 @@ static int bfq_update_next_in_service(struct bfq_sched_data *sd)
return 0;
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
+/* both next loops stop at one of the child entities of the root group */
+#define for_each_entity(entity) \
for (; entity ; entity = entity->parent)
#define for_each_entity_safe(entity, parent) \
for (; entity && ({ parent = entity->parent; 1; }); entity = parent)
-
-static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd,
- int extract,
- struct bfq_data *bfqd);
-
-static struct bfq_group *bfqq_group(struct bfq_queue *bfqq);
-
-static void bfq_update_budget(struct bfq_entity *next_in_service)
+/*
+ * Returns true if this budget changes may let next_in_service->parent
+ * become the next_in_service entity for its parent entity.
+ */
+static bool bfq_update_parent_budget(struct bfq_entity *next_in_service)
{
struct bfq_entity *bfqg_entity;
struct bfq_group *bfqg;
struct bfq_sched_data *group_sd;
+ bool ret = false;
BUG_ON(!next_in_service);
@@ -41,60 +179,68 @@ static void bfq_update_budget(struct bfq_entity *next_in_service)
* as it must never become an in-service entity.
*/
bfqg_entity = bfqg->my_entity;
- if (bfqg_entity)
+ if (bfqg_entity) {
+ if (bfqg_entity->budget > next_in_service->budget)
+ ret = true;
bfqg_entity->budget = next_in_service->budget;
+ }
+
+ return ret;
}
-static int bfq_update_next_in_service(struct bfq_sched_data *sd)
+/*
+ * This function tells whether entity stops being a candidate for next
+ * service, according to the following logic.
+ *
+ * This function is invoked for an entity that is about to be set in
+ * service. If such an entity is a queue, then the entity is no longer
+ * a candidate for next service (i.e, a candidate entity to serve
+ * after the in-service entity is expired). The function then returns
+ * true.
+ *
+ * In contrast, the entity could stil be a candidate for next service
+ * if it is not a queue, and has more than one child. In fact, even if
+ * one of its children is about to be set in service, other children
+ * may still be the next to serve. As a consequence, a non-queue
+ * entity is not a candidate for next-service only if it has only one
+ * child. And only if this condition holds, then the function returns
+ * true for a non-queue entity.
+ */
+static bool bfq_no_longer_next_in_service(struct bfq_entity *entity)
{
- struct bfq_entity *next_in_service;
+ struct bfq_group *bfqg;
- if (sd->in_service_entity)
- /* will update/requeue at the end of service */
- return 0;
+ if (bfq_entity_to_bfqq(entity))
+ return true;
- /*
- * NOTE: this can be improved in many ways, such as returning
- * 1 (and thus propagating upwards the update) only when the
- * budget changes, or caching the bfqq that will be scheduled
- * next from this subtree. By now we worry more about
- * correctness than about performance...
- */
- next_in_service = bfq_lookup_next_entity(sd, 0, NULL);
- sd->next_in_service = next_in_service;
+ bfqg = container_of(entity, struct bfq_group, entity);
- if (next_in_service)
- bfq_update_budget(next_in_service);
+ BUG_ON(bfqg == ((struct bfq_data *)(bfqg->bfqd))->root_group);
+ BUG_ON(bfqg->active_entities == 0);
+ if (bfqg->active_entities == 1)
+ return true;
- return 1;
+ return false;
}
-static void bfq_check_next_in_service(struct bfq_sched_data *sd,
- struct bfq_entity *entity)
-{
- BUG_ON(sd->next_in_service != entity);
-}
-
-static void bfq_update_budget(struct bfq_entity *next_in_service)
+static void bfq_update_parent_budget(struct bfq_entity *next_in_service)
-#else
+#else /* CONFIG_BFQ_GROUP_IOSCHED */
#define for_each_entity(entity) \
for (; entity ; entity = NULL)
#define for_each_entity_safe(entity, parent) \
for (parent = NULL; entity ; entity = parent)
-static int bfq_update_next_in_service(struct bfq_sched_data *sd)
+static bool bfq_update_parent_budget(struct bfq_entity *next_in_service)
{
- return 0;
+ return false;
}
#endif
@@ -105,18 +213,6 @@ static void bfq_update_budget(struct bfq_entity *next_in_service)
-static void bfq_check_next_in_service(struct bfq_sched_data *sd,
- struct bfq_entity *entity)
+static bool bfq_no_longer_next_in_service(struct bfq_entity *entity)
{
+ return true;
}
-static void bfq_update_budget(struct bfq_entity *next_in_service)
-{
-}
-#endif
+#endif /* CONFIG_BFQ_GROUP_IOSCHED */
/*
* Shift for timestamp calculations. This actually limits the maximum
@@ -105,18 +251,6 @@ static void bfq_update_budget(struct bfq_entity *next_in_service)
*/
#define WFQ_SERVICE_SHIFT 22
@@ -6511,7 +6569,7 @@ index a5ed694..4af77f4 100644
static struct bfq_queue *bfq_entity_to_bfqq(struct bfq_entity *entity)
{
struct bfq_queue *bfqq = NULL;
@@ -151,20 +247,36 @@ static u64 bfq_delta(unsigned long service, unsigned long weight)
@@ -151,20 +285,36 @@ static u64 bfq_delta(unsigned long service, unsigned long weight)
static void bfq_calc_finish(struct bfq_entity *entity, unsigned long service)
{
struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
@@ -6550,7 +6608,7 @@ index a5ed694..4af77f4 100644
}
}
@@ -293,10 +405,26 @@ static void bfq_update_min(struct bfq_entity *entity, struct rb_node *node)
@@ -293,10 +443,26 @@ static void bfq_update_min(struct bfq_entity *entity, struct rb_node *node)
static void bfq_update_active_node(struct rb_node *node)
{
struct bfq_entity *entity = rb_entry(node, struct bfq_entity, rb_node);
@@ -6577,7 +6635,7 @@ index a5ed694..4af77f4 100644
}
/**
@@ -386,8 +514,6 @@ static void bfq_active_insert(struct bfq_service_tree *st,
@@ -386,8 +552,6 @@ static void bfq_active_insert(struct bfq_service_tree *st,
BUG_ON(!bfqg);
BUG_ON(!bfqd);
bfqg->active_entities++;
@@ -6586,7 +6644,7 @@ index a5ed694..4af77f4 100644
}
#endif
}
@@ -399,7 +525,7 @@ static void bfq_active_insert(struct bfq_service_tree *st,
@@ -399,7 +563,7 @@ static void bfq_active_insert(struct bfq_service_tree *st,
static unsigned short bfq_ioprio_to_weight(int ioprio)
{
BUG_ON(ioprio < 0 || ioprio >= IOPRIO_BE_NR);
@@ -6595,7 +6653,7 @@ index a5ed694..4af77f4 100644
}
/**
@@ -422,9 +548,9 @@ static void bfq_get_entity(struct bfq_entity *entity)
@@ -422,9 +586,9 @@ static void bfq_get_entity(struct bfq_entity *entity)
struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
if (bfqq) {
@@ -6607,7 +6665,7 @@ index a5ed694..4af77f4 100644
}
}
@@ -499,10 +625,6 @@ static void bfq_active_extract(struct bfq_service_tree *st,
@@ -499,10 +663,6 @@ static void bfq_active_extract(struct bfq_service_tree *st,
BUG_ON(!bfqd);
BUG_ON(!bfqg->active_entities);
bfqg->active_entities--;
@@ -6618,7 +6676,7 @@ index a5ed694..4af77f4 100644
}
#endif
}
@@ -547,12 +669,12 @@ static void bfq_forget_entity(struct bfq_service_tree *st,
@@ -547,12 +707,12 @@ static void bfq_forget_entity(struct bfq_service_tree *st,
BUG_ON(!entity->on_st);
@@ -6633,7 +6691,7 @@ index a5ed694..4af77f4 100644
bfq_put_queue(bfqq);
}
}
@@ -602,7 +724,7 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
@@ -602,7 +762,7 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
if (entity->prio_changed) {
struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
@@ -6642,7 +6700,7 @@ index a5ed694..4af77f4 100644
struct bfq_data *bfqd = NULL;
struct rb_root *root;
#ifdef CONFIG_BFQ_GROUP_IOSCHED
@@ -630,7 +752,10 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
@@ -630,7 +790,10 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
entity->new_weight > BFQ_MAX_WEIGHT) {
pr_crit("update_weight_prio: new_weight %d\n",
entity->new_weight);
@@ -6654,7 +6712,7 @@ index a5ed694..4af77f4 100644
}
entity->orig_weight = entity->new_weight;
if (bfqq)
@@ -661,6 +786,13 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
@@ -661,6 +824,13 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
* associated with its new weight.
*/
if (prev_weight != new_weight) {
@@ -6668,7 +6726,7 @@ index a5ed694..4af77f4 100644
root = bfqq ? &bfqd->queue_weights_tree :
&bfqd->group_weights_tree;
bfq_weights_tree_remove(bfqd, entity, root);
@@ -707,7 +839,7 @@ static void bfq_bfqq_served(struct bfq_queue *bfqq, int served)
@@ -707,7 +877,7 @@ static void bfq_bfqq_served(struct bfq_queue *bfqq, int served)
st = bfq_entity_service_tree(entity);
entity->service += served;
@@ -6677,7 +6735,7 @@ index a5ed694..4af77f4 100644
BUG_ON(st->wsum == 0);
st->vtime += bfq_delta(served, st->wsum);
@@ -716,170 +848,419 @@ static void bfq_bfqq_served(struct bfq_queue *bfqq, int served)
@@ -716,170 +886,419 @@ static void bfq_bfqq_served(struct bfq_queue *bfqq, int served)
#ifdef CONFIG_BFQ_GROUP_IOSCHED
bfqg_stats_set_start_empty_time(bfqq_group(bfqq));
#endif
@@ -6731,17 +6789,17 @@ index a5ed694..4af77f4 100644
+ if (time_ms > 0 && time_ms < timeout_ms)
+ tot_serv_to_charge =
+ (bfqd->bfq_max_budget * time_ms) / timeout_ms;
+
- bfq_log_bfqq(bfqq->bfqd, bfqq, "charge_full_budget");
+ if (tot_serv_to_charge < entity->service)
+ tot_serv_to_charge = entity->service;
- bfq_log_bfqq(bfqq->bfqd, bfqq, "charge_full_budget");
- bfq_bfqq_served(bfqq, entity->budget - entity->service);
+ bfq_log_bfqq(bfqq->bfqd, bfqq,
+ "charge_time: %lu/%u ms, %d/%d/%d sectors",
+ time_ms, timeout_ms, entity->service,
+ tot_serv_to_charge, entity->budget);
- bfq_bfqq_served(bfqq, entity->budget - entity->service);
+
+ /* Increase budget to avoid inconsistencies */
+ if (tot_serv_to_charge > entity->budget)
+ entity->budget = tot_serv_to_charge;
@@ -6948,19 +7006,20 @@ index a5ed694..4af77f4 100644
- * @entity: the entity to activate.
+ * __bfq_requeue_entity - handle requeueing or repositioning of an entity.
+ * @entity: the entity being requeued or repositioned.
*
- * Activate @entity and all the entities on the path from it to the root.
+ *
+ * Requeueing is needed if this entity stops being served, which
+ * happens if a leaf descendant entity has expired. On the other hand,
+ * repositioning is needed if the next_inservice_entity for the child
+ * entity has changed. See the comments inside the function for
+ * details.
+ *
*
- * Activate @entity and all the entities on the path from it to the root.
+ * Basically, this function: 1) removes entity from its active tree if
+ * present there, 2) updates the timestamps of entity and 3) inserts
+ * entity back into its active tree (in the new, right position for
+ * the new values of the timestamps).
+ */
*/
-static void bfq_activate_entity(struct bfq_entity *entity)
+static void __bfq_requeue_entity(struct bfq_entity *entity)
+{
+ struct bfq_sched_data *sd = entity->sched_data;
@@ -7065,8 +7124,7 @@ index a5ed694..4af77f4 100644
+ * @requeue: true if this is a requeue, which implies that bfqq is
+ * being expired; thus ALL its ancestors stop being served and must
+ * therefore be requeued
*/
-static void bfq_activate_entity(struct bfq_entity *entity)
+ */
+static void bfq_activate_requeue_entity(struct bfq_entity *entity,
+ bool non_blocking_wait_rq,
+ bool requeue)
@@ -7186,7 +7244,7 @@ index a5ed694..4af77f4 100644
{
struct bfq_sched_data *sd;
struct bfq_entity *parent;
@@ -887,63 +1268,153 @@ static void bfq_deactivate_entity(struct bfq_entity *entity, int requeue)
@@ -887,63 +1306,154 @@ static void bfq_deactivate_entity(struct bfq_entity *entity, int requeue)
for_each_entity_safe(entity, parent) {
sd = entity->sched_data;
@@ -7309,7 +7367,8 @@ index a5ed694..4af77f4 100644
+ if (!bfq_update_next_in_service(sd, entity) &&
+ !expiration)
+ /*
+ * next_in_service unchanged, and no
+ * next_in_service unchanged or not causing
+ * any change in entity->parent->sd, and no
+ * requeueing needed for expiration: stop
+ * here.
+ */
@@ -7339,13 +7398,13 @@ index a5ed694..4af77f4 100644
- struct bfq_entity *entry;
- struct rb_node *node = st->active.rb_node;
+ struct bfq_entity *root_entity = bfq_root_active_entity(&st->active);
+
+ if (bfq_gt(root_entity->min_start, st->vtime)) {
+ struct bfq_queue *bfqq = bfq_entity_to_bfqq(root_entity);
- entry = rb_entry(node, struct bfq_entity, rb_node);
- if (bfq_gt(entry->min_start, st->vtime)) {
- st->vtime = entry->min_start;
+ if (bfq_gt(root_entity->min_start, st->vtime)) {
+ struct bfq_queue *bfqq = bfq_entity_to_bfqq(root_entity);
+
+ if (bfqq)
+ bfq_log_bfqq(bfqq->bfqd, bfqq,
+ "calc_vtime_jump: new value %llu",
@@ -7373,7 +7432,7 @@ index a5ed694..4af77f4 100644
bfq_forget_idle(st);
}
}
@@ -952,6 +1423,7 @@ static void bfq_update_vtime(struct bfq_service_tree *st)
@@ -952,6 +1462,7 @@ static void bfq_update_vtime(struct bfq_service_tree *st)
* bfq_first_active_entity - find the eligible entity with
* the smallest finish time
* @st: the service tree to select from.
@@ -7381,7 +7440,7 @@ index a5ed694..4af77f4 100644
*
* This function searches the first schedulable entity, starting from the
* root of the tree and going on the left every time on this side there is
@@ -959,7 +1431,8 @@ static void bfq_update_vtime(struct bfq_service_tree *st)
@@ -959,7 +1470,8 @@ static void bfq_update_vtime(struct bfq_service_tree *st)
* the right is followed only if a) the left subtree contains no eligible
* entities and b) no eligible entity has been found yet.
*/
@@ -7391,7 +7450,7 @@ index a5ed694..4af77f4 100644
{
struct bfq_entity *entry, *first = NULL;
struct rb_node *node = st->active.rb_node;
@@ -967,15 +1440,15 @@ static struct bfq_entity *bfq_first_active_entity(struct bfq_service_tree *st)
@@ -967,15 +1479,15 @@ static struct bfq_entity *bfq_first_active_entity(struct bfq_service_tree *st)
while (node) {
entry = rb_entry(node, struct bfq_entity, rb_node);
left:
@@ -7410,7 +7469,7 @@ index a5ed694..4af77f4 100644
node = node->rb_left;
goto left;
}
@@ -993,31 +1466,84 @@ static struct bfq_entity *bfq_first_active_entity(struct bfq_service_tree *st)
@@ -993,31 +1505,84 @@ static struct bfq_entity *bfq_first_active_entity(struct bfq_service_tree *st)
* __bfq_lookup_next_entity - return the first eligible entity in @st.
* @st: the service tree.
*
@@ -7510,7 +7569,7 @@ index a5ed694..4af77f4 100644
return entity;
}
@@ -1025,50 +1551,118 @@ static struct bfq_entity *__bfq_lookup_next_entity(struct bfq_service_tree *st,
@@ -1025,50 +1590,81 @@ static struct bfq_entity *__bfq_lookup_next_entity(struct bfq_service_tree *st,
/**
* bfq_lookup_next_entity - return the first eligible entity in @sd.
* @sd: the sched_data.
@@ -7620,48 +7679,11 @@ index a5ed694..4af77f4 100644
+
+ return sd->next_in_service != sd->in_service_entity;
+}
+
+/*
+ * This function tells whether entity stops being a candidate for next
+ * service, according to the following logic.
+ *
+ * This function is invoked for an entity that is about to be set in
+ * service. If such an entity is a queue, then the entity is no longer
+ * a candidate for next service (i.e, a candidate entity to serve
+ * after the in-service entity is expired). The function then returns
+ * true.
+ *
+ * In contrast, the entity could stil be a candidate for next service
+ * if it is not a queue, and has more than one child. In fact, even if
+ * one of its children is about to be set in service, other children
+ * may still be the next to serve. As a consequence, a non-queue
+ * entity is not a candidate for next-service only if it has only one
+ * child. And only if this condition holds, then the function returns
+ * true for a non-queue entity.
+ */
+static bool bfq_no_longer_next_in_service(struct bfq_entity *entity)
+{
+ struct bfq_group *bfqg;
+
+ if (bfq_entity_to_bfqq(entity))
+ return true;
+
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
+ bfqg = container_of(entity, struct bfq_group, entity);
+
+ BUG_ON(bfqg == ((struct bfq_data *)(bfqg->bfqd))->root_group);
+ BUG_ON(bfqg->active_entities == 0);
+ if (bfqg->active_entities == 1)
+ return true;
+#endif
+
+ return false;
+}
+
/*
* Get next queue for service.
*/
@@ -1083,58 +1677,208 @@ static struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd)
@@ -1083,58 +1679,208 @@ static struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd)
if (bfqd->busy_queues == 0)
return NULL;
@@ -7883,7 +7905,7 @@ index a5ed694..4af77f4 100644
{
BUG_ON(!bfq_bfqq_busy(bfqq));
BUG_ON(!RB_EMPTY_ROOT(&bfqq->sort_list));
@@ -1146,27 +1890,20 @@ static void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq,
@@ -1146,27 +1892,20 @@ static void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq,
BUG_ON(bfqd->busy_queues == 0);
bfqd->busy_queues--;
@@ -7918,7 +7940,7 @@ index a5ed694..4af77f4 100644
}
/*
@@ -1184,16 +1921,11 @@ static void bfq_add_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq)
@@ -1184,16 +1923,11 @@ static void bfq_add_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq)
bfq_mark_bfqq_busy(bfqq);
bfqd->busy_queues++;
@@ -7938,13 +7960,13 @@ index a5ed694..4af77f4 100644
bfqd->wr_busy_queues++;
}
diff --git a/block/bfq.h b/block/bfq.h
index fcce855..57ab51d 100644
index fcce855..bef8244 100644
--- a/block/bfq.h
+++ b/block/bfq.h
@@ -1,5 +1,5 @@
/*
- * BFQ-v7r11 for 4.5.0: data structures and common functions prototypes.
+ * BFQ v8r6 for 4.9.0: data structures and common functions prototypes.
+ * BFQ v8r7 for 4.9.0: data structures and common functions prototypes.
*
* Based on ideas and code from CFQ:
* Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
@@ -0,0 +1,729 @@
block/bfq-cgroup.c | 12 +--
block/bfq-iosched.c | 211 +++++++++++++++++++++++++++++++---------------------
block/bfq-sched.c | 73 ++++++++++++------
block/bfq.h | 4 +-
4 files changed, 180 insertions(+), 120 deletions(-)
diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c
index bbaecd0..a66a723 100644
--- a/block/bfq-cgroup.c
+++ b/block/bfq-cgroup.c
@@ -771,7 +771,6 @@ static void bfq_pd_offline(struct blkg_policy_data *pd)
__bfq_deactivate_entity(entity, false);
bfq_put_async_queues(bfqd, bfqg);
- BUG_ON(entity->tree);
/*
* @blkg is going offline and will be ignored by
@@ -1140,6 +1139,9 @@ static inline void bfqg_stats_update_idle_time(struct bfq_group *bfqg) { }
static inline void bfqg_stats_set_start_idle_time(struct bfq_group *bfqg) { }
static inline void bfqg_stats_update_avg_queue_size(struct bfq_group *bfqg) { }
+static void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,
+ struct bfq_group *bfqg) {}
+
static void bfq_init_entity(struct bfq_entity *entity,
struct bfq_group *bfqg)
{
@@ -1154,13 +1156,7 @@ static void bfq_init_entity(struct bfq_entity *entity,
entity->sched_data = &bfqg->sched_data;
}
-static struct bfq_group *
-bfq_bic_update_cgroup(struct bfq_io_cq *bic, struct bio *bio)
-{
- struct bfq_data *bfqd = bic_to_bfqd(bic);
-
- return bfqd->root_group;
-}
+static void bfq_bic_update_cgroup(struct bfq_io_cq *bic, struct bio *bio) {}
static void bfq_end_wr_async(struct bfq_data *bfqd)
{
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index 78baa07..96b79a0 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -9,7 +9,7 @@
*
* Copyright (C) 2015 Paolo Valente <paolo.valente@unimore.it>
*
- * Copyright (C) 2016 Paolo Valente <paolo.valente@linaro.org>
+ * Copyright (C) 2017 Paolo Valente <paolo.valente@linaro.org>
*
* Licensed under the GPL-2 as detailed in the accompanying COPYING.BFQ
* file.
@@ -107,7 +107,7 @@ static const int bfq_async_charge_factor = 10;
/* Default timeout values, in jiffies, approximating CFQ defaults. */
static const int bfq_timeout = (HZ / 8);
-struct kmem_cache *bfq_pool;
+static struct kmem_cache *bfq_pool;
/* Below this threshold (in ns), we consider thinktime immediate. */
#define BFQ_MIN_TT (2 * NSEC_PER_MSEC)
@@ -483,6 +483,22 @@ static void bfq_weights_tree_add(struct bfq_data *bfqd,
entity->weight_counter = kzalloc(sizeof(struct bfq_weight_counter),
GFP_ATOMIC);
+
+ /*
+ * In the unlucky event of an allocation failure, we just
+ * exit. This will cause the weight of entity to not be
+ * considered in bfq_differentiated_weights, which, in its
+ * turn, causes the scenario to be deemed wrongly symmetric in
+ * case entity's weight would have been the only weight making
+ * the scenario asymmetric. On the bright side, no unbalance
+ * will however occur when entity becomes inactive again (the
+ * invocation of this function is triggered by an activation
+ * of entity). In fact, bfq_weights_tree_remove does nothing
+ * if !entity->weight_counter.
+ */
+ if (unlikely(!entity->weight_counter))
+ return;
+
entity->weight_counter->weight = entity->weight;
rb_link_node(&entity->weight_counter->weights_node, parent, new);
rb_insert_color(&entity->weight_counter->weights_node, root);
@@ -519,13 +535,45 @@ static void bfq_weights_tree_remove(struct bfq_data *bfqd,
entity->weight_counter = NULL;
}
+/*
+ * Return expired entry, or NULL to just start from scratch in rbtree.
+ */
+static struct request *bfq_check_fifo(struct bfq_queue *bfqq,
+ struct request *last)
+{
+ struct request *rq;
+
+ if (bfq_bfqq_fifo_expire(bfqq))
+ return NULL;
+
+ bfq_mark_bfqq_fifo_expire(bfqq);
+
+ rq = rq_entry_fifo(bfqq->fifo.next);
+
+ if (rq == last || ktime_get_ns() < rq->fifo_time)
+ return NULL;
+
+ bfq_log_bfqq(bfqq->bfqd, bfqq, "check_fifo: returned %p", rq);
+ BUG_ON(RB_EMPTY_NODE(&rq->rb_node));
+ return rq;
+}
+
static struct request *bfq_find_next_rq(struct bfq_data *bfqd,
struct bfq_queue *bfqq,
struct request *last)
{
struct rb_node *rbnext = rb_next(&last->rb_node);
struct rb_node *rbprev = rb_prev(&last->rb_node);
- struct request *next = NULL, *prev = NULL;
+ struct request *next, *prev = NULL;
+
+ BUG_ON(list_empty(&bfqq->fifo));
+
+ /* Follow expired path, else get first next available. */
+ next = bfq_check_fifo(bfqq, last);
+ if (next) {
+ BUG_ON(next == last);
+ return next;
+ }
BUG_ON(RB_EMPTY_NODE(&last->rb_node));
@@ -1359,7 +1407,6 @@ static void bfq_bfqq_handle_idle_busy_switch(struct bfq_data *bfqd,
bfq_bfqq_expire(bfqd, bfqd->in_service_queue,
false, BFQ_BFQQ_PREEMPTED);
- BUG_ON(in_serv->entity.budget < 0);
}
}
@@ -1523,12 +1570,15 @@ static void bfq_remove_request(struct request *rq)
elv_rb_del(&bfqq->sort_list, rq);
if (RB_EMPTY_ROOT(&bfqq->sort_list)) {
+ bfqq->next_rq = NULL;
+
BUG_ON(bfqq->entity.budget < 0);
if (bfq_bfqq_busy(bfqq) && bfqq != bfqd->in_service_queue) {
+ BUG_ON(bfqq->ref < 2); /* referred by rq and on tree */
bfq_del_bfqq_busy(bfqd, bfqq, false);
-
- /* bfqq emptied. In normal operation, when
+ /*
+ * bfqq emptied. In normal operation, when
* bfqq is empty, bfqq->entity.service and
* bfqq->entity.budget must contain,
* respectively, the service received and the
@@ -1537,7 +1587,8 @@ static void bfq_remove_request(struct request *rq)
* this last removal occurred while bfqq is
* not in service. To avoid inconsistencies,
* reset both bfqq->entity.service and
- * bfqq->entity.budget.
+ * bfqq->entity.budget, if bfqq has still a
+ * process that may issue I/O requests to it.
*/
bfqq->entity.budget = bfqq->entity.service = 0;
}
@@ -1868,7 +1919,7 @@ static bool bfq_may_be_close_cooperator(struct bfq_queue *bfqq,
* positives. In case bfqq is weight-raised, such false positives
* would evidently degrade latency guarantees for bfqq.
*/
-bool wr_from_too_long(struct bfq_queue *bfqq)
+static bool wr_from_too_long(struct bfq_queue *bfqq)
{
return bfqq->wr_coeff > 1 &&
time_is_before_jiffies(bfqq->last_wr_start_finish +
@@ -2029,7 +2080,8 @@ bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic,
new_bfqq->wr_coeff = bfqq->wr_coeff;
new_bfqq->wr_cur_max_time = bfqq->wr_cur_max_time;
new_bfqq->last_wr_start_finish = bfqq->last_wr_start_finish;
- new_bfqq->wr_start_at_switch_to_srt = bfqq->wr_start_at_switch_to_srt;
+ new_bfqq->wr_start_at_switch_to_srt =
+ bfqq->wr_start_at_switch_to_srt;
if (bfq_bfqq_busy(new_bfqq))
bfqd->wr_busy_queues++;
new_bfqq->entity.prio_changed = 1;
@@ -2072,6 +2124,7 @@ bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic,
*/
new_bfqq->bic = NULL;
bfqq->bic = NULL;
+ /* release process reference to bfqq */
bfq_put_queue(bfqq);
}
@@ -2298,7 +2351,7 @@ static unsigned long bfq_calc_max_budget(struct bfq_data *bfqd)
* function of the estimated peak rate. See comments on
* bfq_calc_max_budget(), and on T_slow and T_fast arrays.
*/
-void update_thr_responsiveness_params(struct bfq_data *bfqd)
+static void update_thr_responsiveness_params(struct bfq_data *bfqd)
{
int dev_type = blk_queue_nonrot(bfqd->queue);
@@ -2333,7 +2386,7 @@ void update_thr_responsiveness_params(struct bfq_data *bfqd)
BFQ_RATE_SHIFT);
}
-void bfq_reset_rate_computation(struct bfq_data *bfqd, struct request *rq)
+static void bfq_reset_rate_computation(struct bfq_data *bfqd, struct request *rq)
{
if (rq != NULL) { /* new rq dispatch now, reset accordingly */
bfqd->last_dispatch = bfqd->first_dispatch = ktime_get_ns() ;
@@ -2350,7 +2403,7 @@ void bfq_reset_rate_computation(struct bfq_data *bfqd, struct request *rq)
bfqd->tot_sectors_dispatched);
}
-void bfq_update_rate_reset(struct bfq_data *bfqd, struct request *rq)
+static void bfq_update_rate_reset(struct bfq_data *bfqd, struct request *rq)
{
u32 rate, weight, divisor;
@@ -2400,7 +2453,7 @@ void bfq_update_rate_reset(struct bfq_data *bfqd, struct request *rq)
* total, and rate is below the current estimated peak rate
* - rate is unreasonably high (> 20M sectors/sec)
*/
- if ((bfqd->peak_rate_samples > (3 * bfqd->sequential_samples)>>2 &&
+ if ((bfqd->sequential_samples < (3 * bfqd->peak_rate_samples)>>2 &&
rate <= bfqd->peak_rate) ||
rate > 20<<BFQ_RATE_SHIFT) {
bfq_log(bfqd,
@@ -2515,7 +2568,7 @@ void bfq_update_rate_reset(struct bfq_data *bfqd, struct request *rq)
* of the observed dispatch rate. The function assumes to be invoked
* on every request dispatch.
*/
-void bfq_update_peak_rate(struct bfq_data *bfqd, struct request *rq)
+static void bfq_update_peak_rate(struct bfq_data *bfqd, struct request *rq)
{
u64 now_ns = ktime_get_ns();
@@ -2616,29 +2669,6 @@ static void bfq_dispatch_insert(struct request_queue *q, struct request *rq)
elv_dispatch_sort(q, rq);
}
-/*
- * Return expired entry, or NULL to just start from scratch in rbtree.
- */
-static struct request *bfq_check_fifo(struct bfq_queue *bfqq)
-{
- struct request *rq = NULL;
-
- if (bfq_bfqq_fifo_expire(bfqq))
- return NULL;
-
- bfq_mark_bfqq_fifo_expire(bfqq);
-
- if (list_empty(&bfqq->fifo))
- return NULL;
-
- rq = rq_entry_fifo(bfqq->fifo.next);
-
- if (ktime_get_ns() < rq->fifo_time)
- return NULL;
-
- return rq;
-}
-
static void __bfq_bfqq_expire(struct bfq_data *bfqd, struct bfq_queue *bfqq)
{
BUG_ON(bfqq != bfqd->in_service_queue);
@@ -2904,8 +2934,8 @@ static bool bfq_bfqq_is_slow(struct bfq_data *bfqd, struct bfq_queue *bfqq,
delta_ktime = ktime_sub(delta_ktime, bfqd->last_budget_start);
delta_usecs = ktime_to_us(delta_ktime);
- /* don't trust short/unrealistic values. */
- if (delta_usecs < 1000 || delta_usecs >= LONG_MAX) {
+ /* don't use too short time intervals */
+ if (delta_usecs < 1000) {
if (blk_queue_nonrot(bfqd->queue))
/*
* give same worst-case guarantees as idling
@@ -2915,7 +2945,7 @@ static bool bfq_bfqq_is_slow(struct bfq_data *bfqd, struct bfq_queue *bfqq,
else /* charge at least one seek */
*delta_ms = bfq_slice_idle / NSEC_PER_MSEC;
- bfq_log(bfqd, "bfq_bfqq_is_slow: unrealistic %u", delta_usecs);
+ bfq_log(bfqd, "bfq_bfqq_is_slow: too short %u", delta_usecs);
return slow;
}
@@ -3067,6 +3097,7 @@ static void bfq_bfqq_expire(struct bfq_data *bfqd,
bool slow;
unsigned long delta = 0;
struct bfq_entity *entity = &bfqq->entity;
+ int ref;
BUG_ON(bfqq != bfqd->in_service_queue);
@@ -3174,12 +3205,15 @@ static void bfq_bfqq_expire(struct bfq_data *bfqd,
__bfq_bfqq_recalc_budget(bfqd, bfqq, reason);
BUG_ON(bfqq->next_rq == NULL &&
bfqq->entity.budget < bfqq->entity.service);
+ ref = bfqq->ref;
__bfq_bfqq_expire(bfqd, bfqq);
- BUG_ON(!bfq_bfqq_busy(bfqq) && reason == BFQ_BFQQ_BUDGET_EXHAUSTED &&
+ BUG_ON(ref > 1 &&
+ !bfq_bfqq_busy(bfqq) && reason == BFQ_BFQQ_BUDGET_EXHAUSTED &&
!bfq_class_idle(bfqq));
- if (!bfq_bfqq_busy(bfqq) &&
+ /* mark bfqq as waiting a request only if a bic still points to it */
+ if (ref > 1 && !bfq_bfqq_busy(bfqq) &&
reason != BFQ_BFQQ_BUDGET_TIMEOUT &&
reason != BFQ_BFQQ_BUDGET_EXHAUSTED)
bfq_mark_bfqq_non_blocking_wait_rq(bfqq);
@@ -3504,14 +3538,29 @@ static struct bfq_queue *bfq_select_queue(struct bfq_data *bfqd)
!bfq_bfqq_must_idle(bfqq))
goto expire;
+check_queue:
+ /*
+ * This loop is rarely executed more than once. Even when it
+ * happens, it is much more convenient to re-execute this loop
+ * than to return NULL and trigger a new dispatch to get a
+ * request served.
+ */
next_rq = bfqq->next_rq;
/*
* If bfqq has requests queued and it has enough budget left to
* serve them, keep the queue, otherwise expire it.
*/
if (next_rq) {
+ BUG_ON(RB_EMPTY_ROOT(&bfqq->sort_list));
+
if (bfq_serv_to_charge(next_rq, bfqq) >
bfq_bfqq_budget_left(bfqq)) {
+ /*
+ * Expire the queue for budget exhaustion,
+ * which makes sure that the next budget is
+ * enough to serve the next request, even if
+ * it comes from the fifo expired path.
+ */
reason = BFQ_BFQQ_BUDGET_EXHAUSTED;
goto expire;
} else {
@@ -3559,9 +3608,16 @@ static struct bfq_queue *bfq_select_queue(struct bfq_data *bfqd)
bfq_bfqq_expire(bfqd, bfqq, false, reason);
new_queue:
bfqq = bfq_set_in_service_queue(bfqd);
- bfq_log(bfqd, "select_queue: new queue %d returned",
- bfqq ? bfqq->pid : 0);
+ if (bfqq) {
+ bfq_log_bfqq(bfqd, bfqq, "select_queue: checking new queue");
+ goto check_queue;
+ }
keep_queue:
+ if (bfqq)
+ bfq_log_bfqq(bfqd, bfqq, "select_queue: returned this queue");
+ else
+ bfq_log(bfqd, "select_queue: no queue returned");
+
return bfqq;
}
@@ -3627,45 +3683,17 @@ static int bfq_dispatch_request(struct bfq_data *bfqd,
struct bfq_queue *bfqq)
{
int dispatched = 0;
- struct request *rq;
+ struct request *rq = bfqq->next_rq;
unsigned long service_to_charge;
BUG_ON(RB_EMPTY_ROOT(&bfqq->sort_list));
-
- /* Follow expired path, else get first next available. */
- rq = bfq_check_fifo(bfqq);
- if (!rq)
- rq = bfqq->next_rq;
+ BUG_ON(!rq);
service_to_charge = bfq_serv_to_charge(rq, bfqq);
- if (service_to_charge > bfq_bfqq_budget_left(bfqq)) {
- /*
- * This may happen if the next rq is chosen in fifo order
- * instead of sector order. The budget is properly
- * dimensioned to be always sufficient to serve the next
- * request only if it is chosen in sector order. The reason
- * is that it would be quite inefficient and little useful
- * to always make sure that the budget is large enough to
- * serve even the possible next rq in fifo order.
- * In fact, requests are seldom served in fifo order.
- *
- * Expire the queue for budget exhaustion, and make sure
- * that the next act_budget is enough to serve the next
- * request, even if it comes from the fifo expired path.
- */
- bfqq->next_rq = rq;
- /*
- * Since this dispatch is failed, make sure that
- * a new one will be performed
- */
- if (!bfqd->rq_in_driver)
- bfq_schedule_dispatch(bfqd);
- BUG_ON(bfqq->entity.budget < bfqq->entity.service);
- goto expire;
- }
+ BUG_ON(service_to_charge > bfq_bfqq_budget_left(bfqq));
BUG_ON(bfqq->entity.budget < bfqq->entity.service);
- /* Finally, insert request into driver dispatch list. */
+
bfq_bfqq_served(bfqq, service_to_charge);
BUG_ON(bfqq->entity.budget < bfqq->entity.service);
@@ -3805,7 +3833,8 @@ static int bfq_dispatch_requests(struct request_queue *q, int force)
* Task holds one reference to the queue, dropped when task exits. Each rq
* in-flight on this queue also holds a reference, dropped when rq is freed.
*
- * Queue lock must be held here.
+ * Queue lock must be held here. Recall not to use bfqq after calling
+ * this function on it.
*/
static void bfq_put_queue(struct bfq_queue *bfqq)
{
@@ -3874,7 +3903,7 @@ static void bfq_exit_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq)
bfq_put_cooperator(bfqq);
- bfq_put_queue(bfqq);
+ bfq_put_queue(bfqq); /* release process reference */
}
static void bfq_init_icq(struct io_cq *icq)
@@ -3973,6 +4002,7 @@ static void bfq_check_ioprio_change(struct bfq_io_cq *bic, struct bio *bio)
bfqq = bic_to_bfqq(bic, false);
if (bfqq) {
+ /* release process reference on this queue */
bfq_put_queue(bfqq);
bfqq = bfq_get_queue(bfqd, bio, BLK_RW_ASYNC, bic);
bic_set_bfqq(bic, bfqq, false);
@@ -4093,14 +4123,20 @@ static struct bfq_queue *bfq_get_queue(struct bfq_data *bfqd,
* prune it.
*/
if (async_bfqq) {
- bfqq->ref++;
+ bfqq->ref++; /*
+ * Extra group reference, w.r.t. sync
+ * queue. This extra reference is removed
+ * only if bfqq->bfqg disappears, to
+ * guarantee that this queue is not freed
+ * until its group goes away.
+ */
bfq_log_bfqq(bfqd, bfqq, "get_queue, bfqq not in async: %p, %d",
bfqq, bfqq->ref);
*async_bfqq = bfqq;
}
out:
- bfqq->ref++;
+ bfqq->ref++; /* get a process reference to this queue */
bfq_log_bfqq(bfqd, bfqq, "get_queue, at end: %p, %d", bfqq, bfqq->ref);
rcu_read_unlock();
return bfqq;
@@ -4274,10 +4310,14 @@ static void bfq_insert_request(struct request_queue *q, struct request *rq)
bfqq->allocated[rq_data_dir(rq)]--;
new_bfqq->ref++;
bfq_clear_bfqq_just_created(bfqq);
- bfq_put_queue(bfqq);
if (bic_to_bfqq(RQ_BIC(rq), 1) == bfqq)
bfq_merge_bfqqs(bfqd, RQ_BIC(rq),
bfqq, new_bfqq);
+ /*
+ * rq is about to be enqueued into new_bfqq,
+ * release rq reference on bfqq
+ */
+ bfq_put_queue(bfqq);
rq->elv.priv[1] = new_bfqq;
bfqq = new_bfqq;
}
@@ -4697,9 +4737,8 @@ static void bfq_shutdown_timer_wq(struct bfq_data *bfqd)
cancel_work_sync(&bfqd->unplug_work);
}
-#ifdef CONFIG_BFQ_GROUP_IOSCHED
static void __bfq_put_async_bfqq(struct bfq_data *bfqd,
- struct bfq_queue **bfqq_ptr)
+ struct bfq_queue **bfqq_ptr)
{
struct bfq_group *root_group = bfqd->root_group;
struct bfq_queue *bfqq = *bfqq_ptr;
@@ -4730,7 +4769,6 @@ static void bfq_put_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg)
__bfq_put_async_bfqq(bfqd, &bfqg->async_idle_bfqq);
}
-#endif
static void bfq_exit_queue(struct elevator_queue *e)
{
@@ -4755,6 +4793,7 @@ static void bfq_exit_queue(struct elevator_queue *e)
#ifdef CONFIG_BFQ_GROUP_IOSCHED
blkcg_deactivate_policy(q, &blkcg_policy_bfq);
#else
+ bfq_put_async_queues(bfqd, bfqd->root_group);
kfree(bfqd->root_group);
#endif
@@ -5229,7 +5268,7 @@ static struct blkcg_policy blkcg_policy_bfq = {
static int __init bfq_init(void)
{
int ret;
- char msg[60] = "BFQ I/O-scheduler: v8r7";
+ char msg[60] = "BFQ I/O-scheduler: v8r10";
#ifdef CONFIG_BFQ_GROUP_IOSCHED
ret = blkcg_policy_register(&blkcg_policy_bfq);
@@ -5255,7 +5294,7 @@ static int __init bfq_init(void)
* be run for a long time.
*/
T_slow[0] = msecs_to_jiffies(3500); /* actually 4 sec */
- T_slow[1] = msecs_to_jiffies(1000); /* actually 1.5 sec */
+ T_slow[1] = msecs_to_jiffies(6000); /* actually 6.5 sec */
T_fast[0] = msecs_to_jiffies(7000); /* actually 8 sec */
T_fast[1] = msecs_to_jiffies(2500); /* actually 3 sec */
diff --git a/block/bfq-sched.c b/block/bfq-sched.c
index 797bce7..70aac56 100644
--- a/block/bfq-sched.c
+++ b/block/bfq-sched.c
@@ -154,7 +154,13 @@ static bool bfq_update_next_in_service(struct bfq_sched_data *sd,
#define for_each_entity(entity) \
for (; entity ; entity = entity->parent)
-#define for_each_entity_safe(entity, parent) \
+/*
+ * For each iteration, compute parent in advance, so as to be safe if
+ * entity is deallocated during the iteration. Such a deallocation may
+ * happen as a consequence of a bfq_put_queue that frees the bfq_queue
+ * containing entity.
+ */
+#define for_each_entity_safe(entity, parent) \
for (; entity && ({ parent = entity->parent; 1; }); entity = parent)
/*
@@ -691,27 +697,31 @@ static void bfq_idle_insert(struct bfq_service_tree *st,
}
/**
- * bfq_forget_entity - remove an entity from the wfq trees.
+ * bfq_forget_entity - do not consider entity any longer for scheduling
* @st: the service tree.
* @entity: the entity being removed.
+ * @is_in_service: true if entity is currently the in-service entity.
*
- * Update the device status and forget everything about @entity, putting
- * the device reference to it, if it is a queue. Entities belonging to
- * groups are not refcounted.
+ * Forget everything about @entity. In addition, if entity represents
+ * a queue, and the latter is not in service, then release the service
+ * reference to the queue (the one taken through bfq_get_entity). In
+ * fact, in this case, there is really no more service reference to
+ * the queue, as the latter is also outside any service tree. If,
+ * instead, the queue is in service, then __bfq_bfqd_reset_in_service
+ * will take care of putting the reference when the queue finally
+ * stops being served.
*/
static void bfq_forget_entity(struct bfq_service_tree *st,
- struct bfq_entity *entity)
+ struct bfq_entity *entity,
+ bool is_in_service)
{
struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
- struct bfq_sched_data *sd;
-
BUG_ON(!entity->on_st);
entity->on_st = false;
st->wsum -= entity->weight;
- if (bfqq) {
- sd = entity->sched_data;
- bfq_log_bfqq(bfqq->bfqd, bfqq, "forget_entity: %p %d",
+ if (bfqq && !is_in_service) {
+ bfq_log_bfqq(bfqq->bfqd, bfqq, "forget_entity (before): %p %d",
bfqq, bfqq->ref);
bfq_put_queue(bfqq);
}
@@ -726,7 +736,8 @@ static void bfq_put_idle_entity(struct bfq_service_tree *st,
struct bfq_entity *entity)
{
bfq_idle_extract(st, entity);
- bfq_forget_entity(st, entity);
+ bfq_forget_entity(st, entity,
+ entity == entity->sched_data->in_service_entity);
}
/**
@@ -1082,6 +1093,12 @@ static void __bfq_activate_entity(struct bfq_entity *entity,
*/
entity->start = min_vstart;
st->wsum += entity->weight;
+ /*
+ * entity is about to be inserted into a service tree,
+ * and then set in service: get a reference to make
+ * sure entity does not disappear until it is no
+ * longer in service or scheduled for service.
+ */
bfq_get_entity(entity);
BUG_ON(entity->on_st && bfqq);
@@ -1264,27 +1281,27 @@ static bool __bfq_deactivate_entity(struct bfq_entity *entity,
{
struct bfq_sched_data *sd = entity->sched_data;
struct bfq_service_tree *st = bfq_entity_service_tree(entity);
- bool was_in_service = entity == sd->in_service_entity;
+ bool is_in_service = entity == sd->in_service_entity;
if (!entity->on_st) { /* entity never activated, or already inactive */
BUG_ON(entity == entity->sched_data->in_service_entity);
return false;
}
- BUG_ON(was_in_service && entity->tree && entity->tree != &st->active);
+ BUG_ON(is_in_service && entity->tree && entity->tree != &st->active);
- if (was_in_service)
+ if (is_in_service)
bfq_calc_finish(entity, entity->service);
if (entity->tree == &st->active)
bfq_active_extract(st, entity);
- else if (!was_in_service && entity->tree == &st->idle)
+ else if (!is_in_service && entity->tree == &st->idle)
bfq_idle_extract(st, entity);
else if (entity->tree)
BUG();
if (!ins_into_idle_tree || !bfq_gt(entity->finish, st->vtime))
- bfq_forget_entity(st, entity);
+ bfq_forget_entity(st, entity, is_in_service);
else
bfq_idle_insert(st, entity);
@@ -1301,7 +1318,7 @@ static void bfq_deactivate_entity(struct bfq_entity *entity,
bool expiration)
{
struct bfq_sched_data *sd;
- struct bfq_entity *parent;
+ struct bfq_entity *parent = NULL;
for_each_entity_safe(entity, parent) {
sd = entity->sched_data;
@@ -1320,8 +1337,8 @@ static void bfq_deactivate_entity(struct bfq_entity *entity,
if (!__bfq_deactivate_entity(entity, ins_into_idle_tree)) {
/*
- * Entity is not any tree any more, so, this
- * deactivation is a no-op, and there is
+ * entity is not in any tree any more, so
+ * this deactivation is a no-op, and there is
* nothing to change for upper-level entities
* (in case of expiration, this can never
* happen).
@@ -1821,14 +1838,16 @@ static struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd)
static void __bfq_bfqd_reset_in_service(struct bfq_data *bfqd)
{
- struct bfq_entity *entity = &bfqd->in_service_queue->entity;
+ struct bfq_queue *in_serv_bfqq = bfqd->in_service_queue;
+ struct bfq_entity *in_serv_entity = &in_serv_bfqq->entity;
+ struct bfq_entity *entity = in_serv_entity;
if (bfqd->in_service_bic) {
put_io_context(bfqd->in_service_bic->icq.ioc);
bfqd->in_service_bic = NULL;
}
- bfq_clear_bfqq_wait_request(bfqd->in_service_queue);
+ bfq_clear_bfqq_wait_request(in_serv_bfqq);
hrtimer_try_to_cancel(&bfqd->idle_slice_timer);
bfqd->in_service_queue = NULL;
@@ -1840,6 +1859,14 @@ static void __bfq_bfqd_reset_in_service(struct bfq_data *bfqd)
*/
for_each_entity(entity)
entity->sched_data->in_service_entity = NULL;
+
+ /*
+ * in_serv_entity is no longer in service, so, if it is in no
+ * service tree either, then release the service reference to
+ * the queue it represents (taken with bfq_get_entity).
+ */
+ if (!in_serv_entity->on_st)
+ bfq_put_queue(in_serv_bfqq);
}
static void bfq_deactivate_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq,
@@ -1904,8 +1931,6 @@ static void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq,
BUG_ON(bfqq->entity.budget < 0);
bfq_deactivate_bfqq(bfqd, bfqq, true, expiration);
-
- BUG_ON(bfqq->entity.budget < 0);
}
/*
diff --git a/block/bfq.h b/block/bfq.h
index a9da002..e3855af 100644
--- a/block/bfq.h
+++ b/block/bfq.h
@@ -1,5 +1,5 @@
/*
- * BFQ v8r7 for 4.9.0: data structures and common functions prototypes.
+ * BFQ v8r10 for 4.9.0: data structures and common functions prototypes.
*
* Based on ideas and code from CFQ:
* Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
@@ -9,7 +9,7 @@
*
* Copyright (C) 2015 Paolo Valente <paolo.valente@unimore.it>
*
- * Copyright (C) 2016 Paolo Valente <paolo.valente@linaro.org>
+ * Copyright (C) 2017 Paolo Valente <paolo.valente@linaro.org>
*/
#ifndef _BFQ_H
@@ -0,0 +1,39 @@
From: Jan Kara <jack@suse.cz>
Subject: [PATCH] jbd2: Fix dbench4 performance regression for 'nobarrier' mounts
Date: Fri, 28 Apr 2017 11:59:34 +0200
Commit b685d3d65ac7 "block: treat REQ_FUA and REQ_PREFLUSH as
synchronous" removed REQ_SYNC flag from WRITE_FUA implementation. Since
JBD2 strips REQ_FUA and REQ_FLUSH flags from submitted IO when the
filesystem is mounted with nobarrier mount option, journal superblock
writes ended up being async writes after this patch and that caused
heavy performance regression for dbench4 benchmark with high number of
processes. In my test setup with HP RAID array with non-volatile write
cache and 32 GB ram, dbench4 runs with 8 processes regressed by ~25%.
Fix the problem by making sure journal superblock writes are always
treated as synchronous since they generally block progress of the
journalling machinery and thus the whole filesystem.
Fixes: b685d3d65ac791406e0dfd8779cc9b3707fea5a3
CC: stable@vger.kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
---
fs/jbd2/journal.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 5adc2fb62b0f..e768126f6a72 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1348,7 +1348,7 @@ static int jbd2_write_superblock(journal_t *journal, int write_flags)
jbd2_superblock_csum_set(journal, sb);
get_bh(bh);
bh->b_end_io = end_buffer_write_sync;
- ret = submit_bh(REQ_OP_WRITE, write_flags, bh);
+ ret = submit_bh(REQ_OP_WRITE, write_flags | REQ_SYNC, bh);
wait_on_buffer(bh);
if (buffer_write_io_error(bh)) {
clear_buffer_write_io_error(bh);
--
2.12.0
@@ -1,108 +0,0 @@
From 633ee407b9d15a75ac9740ba9d3338815e1fcb95 Mon Sep 17 00:00:00 2001
From: Ilya Dryomov <idryomov@gmail.com>
Date: Tue, 21 Mar 2017 13:44:28 +0100
Subject: libceph: force GFP_NOIO for socket allocations
From: Ilya Dryomov <idryomov@gmail.com>
commit 633ee407b9d15a75ac9740ba9d3338815e1fcb95 upstream.
sock_alloc_inode() allocates socket+inode and socket_wq with
GFP_KERNEL, which is not allowed on the writeback path:
Workqueue: ceph-msgr con_work [libceph]
ffff8810871cb018 0000000000000046 0000000000000000 ffff881085d40000
0000000000012b00 ffff881025cad428 ffff8810871cbfd8 0000000000012b00
ffff880102fc1000 ffff881085d40000 ffff8810871cb038 ffff8810871cb148
Call Trace:
[<ffffffff816dd629>] schedule+0x29/0x70
[<ffffffff816e066d>] schedule_timeout+0x1bd/0x200
[<ffffffff81093ffc>] ? ttwu_do_wakeup+0x2c/0x120
[<ffffffff81094266>] ? ttwu_do_activate.constprop.135+0x66/0x70
[<ffffffff816deb5f>] wait_for_completion+0xbf/0x180
[<ffffffff81097cd0>] ? try_to_wake_up+0x390/0x390
[<ffffffff81086335>] flush_work+0x165/0x250
[<ffffffff81082940>] ? worker_detach_from_pool+0xd0/0xd0
[<ffffffffa03b65b1>] xlog_cil_force_lsn+0x81/0x200 [xfs]
[<ffffffff816d6b42>] ? __slab_free+0xee/0x234
[<ffffffffa03b4b1d>] _xfs_log_force_lsn+0x4d/0x2c0 [xfs]
[<ffffffff811adc1e>] ? lookup_page_cgroup_used+0xe/0x30
[<ffffffffa039a723>] ? xfs_reclaim_inode+0xa3/0x330 [xfs]
[<ffffffffa03b4dcf>] xfs_log_force_lsn+0x3f/0xf0 [xfs]
[<ffffffffa039a723>] ? xfs_reclaim_inode+0xa3/0x330 [xfs]
[<ffffffffa03a62c6>] xfs_iunpin_wait+0xc6/0x1a0 [xfs]
[<ffffffff810aa250>] ? wake_atomic_t_function+0x40/0x40
[<ffffffffa039a723>] xfs_reclaim_inode+0xa3/0x330 [xfs]
[<ffffffffa039ac07>] xfs_reclaim_inodes_ag+0x257/0x3d0 [xfs]
[<ffffffffa039bb13>] xfs_reclaim_inodes_nr+0x33/0x40 [xfs]
[<ffffffffa03ab745>] xfs_fs_free_cached_objects+0x15/0x20 [xfs]
[<ffffffff811c0c18>] super_cache_scan+0x178/0x180
[<ffffffff8115912e>] shrink_slab_node+0x14e/0x340
[<ffffffff811afc3b>] ? mem_cgroup_iter+0x16b/0x450
[<ffffffff8115af70>] shrink_slab+0x100/0x140
[<ffffffff8115e425>] do_try_to_free_pages+0x335/0x490
[<ffffffff8115e7f9>] try_to_free_pages+0xb9/0x1f0
[<ffffffff816d56e4>] ? __alloc_pages_direct_compact+0x69/0x1be
[<ffffffff81150cba>] __alloc_pages_nodemask+0x69a/0xb40
[<ffffffff8119743e>] alloc_pages_current+0x9e/0x110
[<ffffffff811a0ac5>] new_slab+0x2c5/0x390
[<ffffffff816d71c4>] __slab_alloc+0x33b/0x459
[<ffffffff815b906d>] ? sock_alloc_inode+0x2d/0xd0
[<ffffffff8164bda1>] ? inet_sendmsg+0x71/0xc0
[<ffffffff815b906d>] ? sock_alloc_inode+0x2d/0xd0
[<ffffffff811a21f2>] kmem_cache_alloc+0x1a2/0x1b0
[<ffffffff815b906d>] sock_alloc_inode+0x2d/0xd0
[<ffffffff811d8566>] alloc_inode+0x26/0xa0
[<ffffffff811da04a>] new_inode_pseudo+0x1a/0x70
[<ffffffff815b933e>] sock_alloc+0x1e/0x80
[<ffffffff815ba855>] __sock_create+0x95/0x220
[<ffffffff815baa04>] sock_create_kern+0x24/0x30
[<ffffffffa04794d9>] con_work+0xef9/0x2050 [libceph]
[<ffffffffa04aa9ec>] ? rbd_img_request_submit+0x4c/0x60 [rbd]
[<ffffffff81084c19>] process_one_work+0x159/0x4f0
[<ffffffff8108561b>] worker_thread+0x11b/0x530
[<ffffffff81085500>] ? create_worker+0x1d0/0x1d0
[<ffffffff8108b6f9>] kthread+0xc9/0xe0
[<ffffffff8108b630>] ? flush_kthread_worker+0x90/0x90
[<ffffffff816e1b98>] ret_from_fork+0x58/0x90
[<ffffffff8108b630>] ? flush_kthread_worker+0x90/0x90
Use memalloc_noio_{save,restore}() to temporarily force GFP_NOIO here.
Link: http://tracker.ceph.com/issues/19309
Reported-by: Sergey Jerusalimov <wintchester@gmail.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/ceph/messenger.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -7,6 +7,7 @@
#include <linux/kthread.h>
#include <linux/net.h>
#include <linux/nsproxy.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/socket.h>
#include <linux/string.h>
@@ -469,11 +470,16 @@ static int ceph_tcp_connect(struct ceph_
{
struct sockaddr_storage *paddr = &con->peer_addr.in_addr;
struct socket *sock;
+ unsigned int noio_flag;
int ret;
BUG_ON(con->sock);
+
+ /* sock_create_kern() allocates with GFP_KERNEL */
+ noio_flag = memalloc_noio_save();
ret = sock_create_kern(read_pnet(&con->msgr->net), paddr->ss_family,
SOCK_STREAM, IPPROTO_TCP, &sock);
+ memalloc_noio_restore(noio_flag);
if (ret)
return ret;
sock->sk->sk_allocation = GFP_NOFS;
@@ -0,0 +1,117 @@
From 5294b83086cc1c35b4efeca03644cf9d12282e5b Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Tue, 25 Apr 2017 19:08:18 +0200
Subject: [PATCH] macsec: dynamically allocate space for sglist
We call skb_cow_data, which is good anyway to ensure we can actually
modify the skb as such (another error from prior). Now that we have the
number of fragments required, we can safely allocate exactly that amount
of memory.
Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver")
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Acked-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/macsec.c | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index dbab05a..49ce4e9 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -617,7 +617,8 @@ static void macsec_encrypt_done(struct crypto_async_request *base, int err)
static struct aead_request *macsec_alloc_req(struct crypto_aead *tfm,
unsigned char **iv,
- struct scatterlist **sg)
+ struct scatterlist **sg,
+ int num_frags)
{
size_t size, iv_offset, sg_offset;
struct aead_request *req;
@@ -629,7 +630,7 @@ static struct aead_request *macsec_alloc_req(struct crypto_aead *tfm,
size = ALIGN(size, __alignof__(struct scatterlist));
sg_offset = size;
- size += sizeof(struct scatterlist) * (MAX_SKB_FRAGS + 1);
+ size += sizeof(struct scatterlist) * num_frags;
tmp = kmalloc(size, GFP_ATOMIC);
if (!tmp)
@@ -649,6 +650,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
{
int ret;
struct scatterlist *sg;
+ struct sk_buff *trailer;
unsigned char *iv;
struct ethhdr *eth;
struct macsec_eth_header *hh;
@@ -723,7 +725,14 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
return ERR_PTR(-EINVAL);
}
- req = macsec_alloc_req(tx_sa->key.tfm, &iv, &sg);
+ ret = skb_cow_data(skb, 0, &trailer);
+ if (unlikely(ret < 0)) {
+ macsec_txsa_put(tx_sa);
+ kfree_skb(skb);
+ return ERR_PTR(ret);
+ }
+
+ req = macsec_alloc_req(tx_sa->key.tfm, &iv, &sg, ret);
if (!req) {
macsec_txsa_put(tx_sa);
kfree_skb(skb);
@@ -732,7 +741,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
macsec_fill_iv(iv, secy->sci, pn);
- sg_init_table(sg, MAX_SKB_FRAGS + 1);
+ sg_init_table(sg, ret);
skb_to_sgvec(skb, sg, 0, skb->len);
if (tx_sc->encrypt) {
@@ -917,6 +926,7 @@ static struct sk_buff *macsec_decrypt(struct sk_buff *skb,
{
int ret;
struct scatterlist *sg;
+ struct sk_buff *trailer;
unsigned char *iv;
struct aead_request *req;
struct macsec_eth_header *hdr;
@@ -927,7 +937,12 @@ static struct sk_buff *macsec_decrypt(struct sk_buff *skb,
if (!skb)
return ERR_PTR(-ENOMEM);
- req = macsec_alloc_req(rx_sa->key.tfm, &iv, &sg);
+ ret = skb_cow_data(skb, 0, &trailer);
+ if (unlikely(ret < 0)) {
+ kfree_skb(skb);
+ return ERR_PTR(ret);
+ }
+ req = macsec_alloc_req(rx_sa->key.tfm, &iv, &sg, ret);
if (!req) {
kfree_skb(skb);
return ERR_PTR(-ENOMEM);
@@ -936,7 +951,7 @@ static struct sk_buff *macsec_decrypt(struct sk_buff *skb,
hdr = (struct macsec_eth_header *)skb->data;
macsec_fill_iv(iv, sci, ntohl(hdr->packet_number));
- sg_init_table(sg, MAX_SKB_FRAGS + 1);
+ sg_init_table(sg, ret);
skb_to_sgvec(skb, sg, 0, skb->len);
if (hdr->tci_an & MACSEC_TCI_E) {
@@ -2716,7 +2731,7 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
}
#define MACSEC_FEATURES \
- (NETIF_F_SG | NETIF_F_HIGHDMA)
+ (NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST)
static struct lock_class_key macsec_netdev_addr_lock_key;
static int macsec_dev_init(struct net_device *dev)
--
2.10.2
+14 -4
View File
@@ -130,7 +130,8 @@ block-Make-CFQ-default-to-IOPS-mode-on-SSDs.patch
block-cgroups-kconfig-build-bits-for-BFQ-v7r11-4.5.0.patch
block-introduce-the-BFQ-v7r11-I-O-sched-for-4.5.0.patch
block-bfq-add-Early-Queue-Merge-EQM-to-BFQ-v7r11-for.patch
block-Turn-into-BFQ-v8r6-for-4.9.0.patch
block-Turn-into-BFQ-v8r7-for-4.9.0.patch
block-update-bfq-from-v8r7-to-v8r10.patch
# new macbooks
block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch
@@ -159,6 +160,9 @@ fs-aufs-4.9-modular.patch
# needed for mdadm: imsm: enable bad block support for imsm metadata
fs-seq_file-reset-iterator-to-first-record-for-zero-off.patch
# performance regression fix
fs-jbd2-Fix-dbench4-performance-regression-for-nobarrier-mounts.patch
###
### FireWire
###
@@ -266,12 +270,12 @@ net-wireless-rtlwifi-Fix-kernel-oops-introduced-with-commit-e4965.patch
# update rtl8xxxu for mga#20508
net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch
# ceph
net-libceph-force-gfp_noio-for-socket-allocations.patch
# WireGuard support
net-wireguard.patch
# CVE-2017-7477
net-macsec-dynamically-allocate-space-for-sglist.patch
###
### Platform drivers
###
@@ -301,6 +305,12 @@ include-kbuild-export-pci_ids.patch
sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch
sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch
# add support for Gigabyte GA-AX370 Gaming 5 with dual codecs (TTL: 4.12)
sound-ALSA-hda-A-new-flag-to-enforce-prefix-to-each-pin.patch
sound-ALSA-hda-Allow-to-enable-disable-vmaster-build-expli.patch
sound-ALSA-hda-Support-Gigabyte-Gaming-board-with-dual-Rea.patch
sound-ALSA-hda-Use-a-helper-function-for-renaming-kctl-nam.patch
###
### Staging
###
@@ -0,0 +1,68 @@
From 9f3dadb156692e15933a4a97ef659f65151be4a1 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 10 Apr 2017 17:12:33 +0200
Subject: [PATCH 1/4] ALSA: hda - A new flag to enforce prefix to each pin
This is a preliminary patch for a smooth multi-codec support, and it
introduces a new flag, force_pin_prefix, to struct hda_codec.
This flag is used to force to add the pin location prefix to each
input pin. For example, when there is only one microphone pin,
usually the auto-parser assigns the string "Mic". With this flag on,
it'll be like "Front Mic". Also, the creation of "Master" or "PCM"
playback volume for a single pin is suppressed, too.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=195305
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
sound/pci/hda/hda_auto_parser.c | 1 +
sound/pci/hda/hda_codec.h | 1 +
sound/pci/hda/hda_generic.c | 2 ++
3 files changed, 4 insertions(+)
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index a03cf68..d3ea731 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -580,6 +580,7 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec,
has_multiple_pins = 1;
if (has_multiple_pins && type == AUTO_PIN_MIC)
has_multiple_pins &= check_mic_location_need(codec, cfg, input);
+ has_multiple_pins |= codec->force_pin_prefix;
return hda_get_input_pin_label(codec, &cfg->inputs[input],
cfg->inputs[input].pin,
has_multiple_pins);
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index f17f252..d6fb2d5 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -256,6 +256,7 @@ struct hda_codec {
unsigned int dump_coef:1; /* dump processing coefs in codec proc file */
unsigned int power_save_node:1; /* advanced PM for each widget */
unsigned int auto_runtime_pm:1; /* enable automatic codec runtime pm */
+ unsigned int force_pin_prefix:1; /* Add location prefix */
#ifdef CONFIG_PM
unsigned long power_on_acct;
unsigned long power_off_acct;
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index e7c8f4f..4438328 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -1125,6 +1125,7 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
*index = 0;
if (cfg->line_outs == 1 && !spec->multi_ios &&
+ !codec->force_pin_prefix &&
!cfg->hp_outs && !cfg->speaker_outs)
return spec->vmaster_mute.hook ? "PCM" : "Master";
@@ -1132,6 +1133,7 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
* use it master (or "PCM" if a vmaster hook is present)
*/
if (spec->multiout.num_dacs == 1 && !spec->mixer_nid &&
+ !codec->force_pin_prefix &&
!spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0])
return spec->vmaster_mute.hook ? "PCM" : "Master";
--
2.10.2
@@ -0,0 +1,78 @@
From 7480316c265c9fcdbf73b1b8dec061b893b7e987 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 10 Apr 2017 17:37:34 +0200
Subject: [PATCH 2/4] ALSA: hda - Allow to enable/disable vmaster build
explicitly
Another preliminary patch for the dual-codec support: since the
support of vmaster over multiple codecs is difficult, simply disable
it by a new flag to hda_codec struct. A new user hint is added as
well for consistency.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
Documentation/sound/hd-audio/notes.rst | 2 ++
sound/pci/hda/hda_generic.c | 7 +++++--
sound/pci/hda/hda_generic.h | 1 +
3 files changed, 8 insertions(+), 2 deletions(-)
#diff --git a/Documentation/sound/hd-audio/notes.rst b/Documentation/sound/hd-audio/notes.rst
#index 9eeb9b4..f59c3cd 100644
#--- a/Documentation/sound/hd-audio/notes.rst
#+++ b/Documentation/sound/hd-audio/notes.rst
#@@ -494,6 +494,8 @@ add_hp_mic (bool)
# hp_mic_detect (bool)
# enable/disable the hp/mic shared input for a single built-in mic
# case; default true
#+vmaster (bool)
#+ enable/disable the virtual Master control; default true
# mixer_nid (int)
# specifies the widget NID of the analog-loopback mixer
#
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 4438328..2842c82 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -196,6 +196,9 @@ static void parse_user_hints(struct hda_codec *codec)
val = snd_hda_get_bool_hint(codec, "hp_mic_detect");
if (val >= 0)
spec->suppress_hp_mic_detect = !val;
+ val = snd_hda_get_bool_hint(codec, "vmaster");
+ if (val >= 0)
+ spec->suppress_vmaster = !val;
if (!snd_hda_get_int_hint(codec, "mixer_nid", &val))
spec->mixer_nid = val;
@@ -5033,7 +5036,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
}
/* if we have no master control, let's create it */
- if (!spec->no_analog &&
+ if (!spec->no_analog && !spec->suppress_vmaster &&
!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
spec->vmaster_tlv, slave_pfxs,
@@ -5041,7 +5044,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
if (err < 0)
return err;
}
- if (!spec->no_analog &&
+ if (!spec->no_analog && !spec->suppress_vmaster &&
!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
NULL, slave_pfxs,
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index f66fc7e..6177231 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -229,6 +229,7 @@ struct hda_gen_spec {
unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */
unsigned int power_down_unused:1; /* power down unused widgets */
unsigned int dac_min_mute:1; /* minimal = mute for DACs */
+ unsigned int suppress_vmaster:1; /* don't create vmaster kctls */
/* other internal flags */
unsigned int no_analog:1; /* digital I/O only */
--
2.10.2
@@ -0,0 +1,122 @@
From 7beb3a6e9335d13872f24566b451f8371edd238f Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 10 Apr 2017 18:05:52 +0200
Subject: [PATCH 3/4] ALSA: hda - Support Gigabyte Gaming board with dual
Realtek codecs
This patch adds some workarounds to make Gigabyte GA-AX370 Gaming 5
board working without the conflicts of kctls, etc. In general, the
dual codec configs result in the conflicts of the following stuff:
- Master controls
- Capture controls
- Analog loopback controls
In addition, the auto-mute and the auto-mic can't work well among
multiple codecs.
The current "solution" is to disable all these features, and use UCM
for a better PulseAudio management. For a dedicated UCM profile, the
patch overrides the card longname so that the system an get a unique
profile path.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=195305
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
sound/pci/hda/patch_realtek.c | 61 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 9371f1a..e81cf83 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -1800,6 +1800,7 @@ enum {
ALC882_FIXUP_NO_PRIMARY_HP,
ALC887_FIXUP_ASUS_BASS,
ALC887_FIXUP_BASS_CHMAP,
+ ALC1220_FIXUP_GB_DUAL_CODECS,
};
static void alc889_fixup_coef(struct hda_codec *codec,
@@ -1962,6 +1963,61 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
static void alc_fixup_bass_chmap(struct hda_codec *codec,
const struct hda_fixup *fix, int action);
+/* For dual-codec configuration, we need to disable some features to avoid
+ * conflicts of kctls and PCM streams
+ */
+static void alc_fixup_dual_codecs(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+ /* disable vmaster */
+ spec->gen.suppress_vmaster = 1;
+ /* auto-mute and auto-mic switch don't work with multiple codecs */
+ spec->gen.suppress_auto_mute = 1;
+ spec->gen.suppress_auto_mic = 1;
+ /* disable aamix as well */
+ spec->gen.mixer_nid = 0;
+ /* add location prefix to avoid conflicts */
+ codec->force_pin_prefix = 1;
+}
+
+static void rename_ctl(struct hda_codec *codec, const char *oldname,
+ const char *newname)
+{
+ struct snd_kcontrol *kctl;
+
+ kctl = snd_hda_find_mixer_ctl(codec, oldname);
+ if (kctl)
+ strcpy(kctl->id.name, newname);
+}
+
+static void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ alc_fixup_dual_codecs(codec, fix, action);
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ /* override card longname to provide a unique UCM profile */
+ strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs");
+ break;
+ case HDA_FIXUP_ACT_BUILD:
+ /* rename Capture controls depending on the codec */
+ rename_ctl(codec, "Capture Volume",
+ codec->addr == 0 ?
+ "Rear-Panel Capture Volume" :
+ "Front-Panel Capture Volume");
+ rename_ctl(codec, "Capture Switch",
+ codec->addr == 0 ?
+ "Rear-Panel Capture Switch" :
+ "Front-Panel Capture Switch");
+ break;
+ }
+}
+
static const struct hda_fixup alc882_fixups[] = {
[ALC882_FIXUP_ABIT_AW9D_MAX] = {
.type = HDA_FIXUP_PINS,
@@ -2198,6 +2254,10 @@ static const struct hda_fixup alc882_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_bass_chmap,
},
+ [ALC1220_FIXUP_GB_DUAL_CODECS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc1220_fixup_gb_dual_codecs,
+ },
};
static const struct snd_pci_quirk alc882_fixup_tbl[] = {
@@ -2267,6 +2327,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
--
2.10.2
@@ -0,0 +1,42 @@
From 56798e6b3a2264b58d50b93cfd66586ede77d661 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Tue, 11 Apr 2017 08:10:52 +0200
Subject: [PATCH 4/4] ALSA: hda - Use a helper function for renaming kctl names
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
sound/pci/hda/patch_realtek.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index e81cf83..57eeefd 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -4724,7 +4724,6 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
{ 0x1b, 0x21114000 }, /* dock speaker pin */
{}
};
- struct snd_kcontrol *kctl;
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
@@ -4739,12 +4738,10 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
/* this is a bit tricky; give more sane names for the main
* (tablet) speaker and the dock speaker, respectively
*/
- kctl = snd_hda_find_mixer_ctl(codec, "Speaker Playback Switch");
- if (kctl)
- strcpy(kctl->id.name, "Dock Speaker Playback Switch");
- kctl = snd_hda_find_mixer_ctl(codec, "Bass Speaker Playback Switch");
- if (kctl)
- strcpy(kctl->id.name, "Speaker Playback Switch");
+ rename_ctl(codec, "Speaker Playback Switch",
+ "Dock Speaker Playback Switch");
+ rename_ctl(codec, "Bass Speaker Playback Switch",
+ "Speaker Playback Switch");
break;
}
}
--
2.10.2
+12 -6
View File
@@ -28,8 +28,8 @@
</BuildDependencies>
<Patches>
<!-- Linux patches -->
<Patch level="1" compressionType="xz">patches/linux/patch-4.9.21.xz</Patch>
<!-- Mageia Linux patches // compatible with http://svnweb.mageia.org/packages/cauldron/kernel/releases/4.9.20/1.mga6/PATCHES/patches/series-->
<Patch level="1" compressionType="xz">patches/linux/patch-4.9.27.xz</Patch>
<!-- Mageia Linux patches // compatible with http://svnweb.mageia.org/packages/cauldron/kernel/releases/4.9.27/1.mga6/PATCHES/patches/series-->
<!--stable patches-->
<!--CVE-2016-8405-->
<!--other patches-->
@@ -59,7 +59,8 @@
<!--Patch level="1">patches/mageia/block-cgroups-kconfig-build-bits-for-BFQ-v7r11-4.5.0.patch</Patch>
<Patch level="1">patches/mageia/block-introduce-the-BFQ-v7r11-I-O-sched-for-4.5.0.patch</Patch>
<Patch level="1">patches/mageia/block-bfq-add-Early-Queue-Merge-EQM-to-BFQ-v7r11-for.patch</Patch>
<Patch level="1">patches/mageia/block-Turn-into-BFQ-v8r6-for-4.9.0.patch</Patch>--><!--2-->
<Patch level="1">patches/mageia/block-Turn-into-BFQ-v8r7-for-4.9.0.patch</Patch>
<Patch level="1">patches/mageia/block-update-bfq-from-v8r7-to-v8r10.patch</Patch><2-->
<Patch level="1">patches/mageia/block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch</Patch>
<Patch level="1">patches/mageia/char-tpm-tpm_crb-implement-tpm-crb-idle-state.patch</Patch>
<Patch level="1">patches/mageia/char-tmp-tpm_crb-fix-Intel-PTT-hw-bug-during-idle-state.patch</Patch>
@@ -69,6 +70,7 @@
<Patch level="1">patches/fs-aufs-4.9-posix_acl.patch</Patch>
<Patch level="1">patches/mageia/fs-aufs-4.9-modular.patch</Patch>
<Patch level="1">patches/mageia/fs-seq_file-reset-iterator-to-first-record-for-zero-off.patch</Patch>
<Patch level="1">patches/mageia/fs-jbd2-Fix-dbench4-performance-regression-for-nobarrier-mounts.patch</Patch>
<Patch level="1">patches/mageia/firewire-ieee1394-module-aliases.patch</Patch>
<Patch level="1">patches/mageia/char-agp-intel-new-Q57-id.patch</Patch>
<!--remove external mach64 support for buildfix-->
@@ -112,14 +114,18 @@
<Patch level="1">patches/mageia/net-wireless-rtlwifi-Use-dev_kfree_skb_irq-instead-of-kfree_skb.patch</Patch>
<Patch level="1">patches/mageia/net-wireless-rtlwifi-Fix-kernel-oops-introduced-with-commit-e4965.patch</Patch>
<Patch level="1">patches/mageia/net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch</Patch>
<!--Patch level="1">patches/mageia/net-libceph-force-gfp_noio-for-socket-allocations.patch</Patch-->
<Patch level="1">patches/mageia/net-wireguard.patch</Patch>
<Patch level="1">patches/mageia/net-macsec-dynamically-allocate-space-for-sglist.patch</Patch>
<Patch level="1">patches/mageia/platform-x86-add-shuttle-wmi-driver.patch</Patch>
<Patch level="1">patches/mageia/platform-x86-shuttle-wmi-drop-devinit-exit.patch</Patch>
<Patch level="1">patches/mageia/platform-x86-shuttle-wmi-4.2-buildfix.patch</Patch>
<Patch level="1">patches/mageia/include-kbuild-export-pci_ids.patch</Patch>
<Patch level="1">patches/mageia/sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch</Patch>
<Patch level="1">patches/mageia/sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch</Patch>
<Patch level="1">patches/mageia/sound-ALSA-hda-A-new-flag-to-enforce-prefix-to-each-pin.patch</Patch>
<Patch level="1">patches/mageia/sound-ALSA-hda-Allow-to-enable-disable-vmaster-build-expli.patch</Patch>
<Patch level="1">patches/mageia/sound-ALSA-hda-Support-Gigabyte-Gaming-board-with-dual-Rea.patch</Patch>
<Patch level="1">patches/mageia/sound-ALSA-hda-Use-a-helper-function-for-renaming-kctl-nam.patch</Patch>
<Patch level="1">patches/mageia/hid-usbhid-IBM-BladeCenterHS20-quirk.patch</Patch>
<Patch level="1">patches/mageia/usb-storage-unusual_devs-add-id.patch</Patch>
<Patch level="1">patches/mageia/usb-storage-unusual_devs-add-id-2.6.37-buildfix.patch</Patch>
@@ -208,8 +214,8 @@
<History>
<Update release="9">
<Date>2017-03-30</Date>
<Version>4.9.21</Version>
<Date>2017-05-09</Date>
<Version>4.9.27</Version>
<Comment>Version Bump.</Comment>
<Type package="kernel">security</Type>
<Requires>